Skip to content

Commit

Permalink
Added sample application (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
Guy Baron committed Sep 29, 2019
1 parent 0cd9890 commit 43af4d4
Show file tree
Hide file tree
Showing 17 changed files with 835 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ the v1.x branch contains the latest stable releases of grabbit and one should tr

## Basic Usage

### See complete application in the examples/vacation_app folder

The following outlines the basic usage of grabbit.
For a complete view of how you would use grabbit including how to write saga's and handle deadlettering refer to grabbit/tests package

Expand Down
1 change: 1 addition & 0 deletions examples/vacation_app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vacation_app
1 change: 1 addition & 0 deletions examples/vacation_app/.gitingnore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vacation_app
35 changes: 35 additions & 0 deletions examples/vacation_app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## grabbit example vacation app

The following example simulates a vacation booking app and demonstrates the use of grabbit
to manage the booking process.

The app is made up out of the following components

- The client, a console app that you enter your vacation destination and calls the booking service to
book the vacation.

- Booking Service manages the booking saga calling the hotels and flights services to book hotels and flights for the requested destination. it handles as well as applying flight cancelation in case the hotel service can not book a hotel.
The booking saga sends back a message to the client with the result of the booking request once the saga completes.

- Flights Service, books flights to the requested destination and replies back the response.
The flight service.

- Hotels Service, books hotels for the requested destination and replies back the response.
In this example requesting to book a vacation in Oslo results in a reply message with a Failed status
Triggering the booking saga to send a command to the flight service to cancel the booked flights.

## building and running the example

- go build
- docker-compose up
- run the booking servce: vacation_app booking
- run the hotels servce: vacation_app hotels
- run the flights servce: vacation_app flights
- run the client: vacation_app client

Once the services are running you can enter a vacation destination in the client app which will invoke the booking saga which will orchestrate the flights and hotels services.


You can see a trace of the calls by browsing to the Jeager client at http://localhost:16686


41 changes: 41 additions & 0 deletions examples/vacation_app/cmd/booking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd

import (
"bufio"
"fmt"
"os"
"vacation_app/trace"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"vacation_app/saga"
)

func init() {
rootCmd.AddCommand(runBookingServiceeCmd)
}

var runBookingServiceeCmd = &cobra.Command{
Use: "booking",
Short: "Run the booking service",
Run: func(cmd *cobra.Command, args []string) {
svcName := "booking-service"
closer, err := trace.CreatetJeagerTracer(svcName)

if err != nil {
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
return
}

defer closer.Close()
gb := createBus(svcName)

gb.RegisterSaga(&saga.BookingSaga{})
gb.Start()
defer gb.Shutdown()

fmt.Print("Booking service running...press any key to exit...\n")
reader := bufio.NewReader(os.Stdin)
reader.ReadString('\n')
},
}
66 changes: 66 additions & 0 deletions examples/vacation_app/cmd/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package cmd

import (
"bufio"
"context"
"fmt"
"os"
"strings"
"vacation_app/messages"
"vacation_app/trace"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/wework/grabbit/gbus"
)


var runClientCmd = &cobra.Command{
Use: "client",
Short: "Run the client app",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("\033]0;Title goes here\007")
log.SetFormatter(&log.TextFormatter{ForceColors: true})
log.SetLevel(log.ErrorLevel)

svcName := "client"
closer, err := trace.CreatetJeagerTracer(svcName)

if err != nil {
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
return
}
defer closer.Close()
gb := createBus(svcName)

gb.HandleMessage(messages.BookingComplete{}, HandleBookingComplete)
gb.Start()
defer gb.Shutdown()

for {
fmt.Print("Enter destination ...\n")
reader := bufio.NewReader(os.Stdin)
dest, _ := reader.ReadString('\n')
dest = strings.TrimSpace(dest)
bookVacationCmd := gbus.NewBusMessage(messages.BookVacationCmd{
Destination: dest,
})

gb.Send(context.Background(), "booking-service", bookVacationCmd)

fmt.Printf("booking vacation for destination %s\n", dest)

}
},
}

func HandleBookingComplete(invocation gbus.Invocation, message *gbus.BusMessage) error {
bookingComplete := message.Payload.(*messages.BookingComplete)
if bookingComplete.Success {
fmt.Printf("booking completed succesfully\n")

} else {
fmt.Printf("failed to book vacation\n")
}
return nil
}
64 changes: 64 additions & 0 deletions examples/vacation_app/cmd/flights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"bufio"
"fmt"
"os"
"vacation_app/trace"
"vacation_app/messages"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/wework/grabbit/gbus"
)



var runFlightsgServiceCmd = &cobra.Command{
Use: "flights",
Short: "Run the flights service",
Run: func(cmd *cobra.Command, args []string) {
svcName := "flights-service"
closer, err := trace.CreatetJeagerTracer(svcName)

if err != nil {
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
return
}

defer closer.Close()
gb := createBus(svcName)

gb.HandleMessage(messages.BookFlightsCmd{}, HandleBookFlightCommand)
gb.HandleMessage(messages.CancelFlightsCmd{}, HandleCancelFlightCommand)

gb.Start()
defer gb.Shutdown()

fmt.Print("Flights service running...press any key to exit...\n")
reader := bufio.NewReader(os.Stdin)
reader.ReadString('\n')
},
}

func HandleBookFlightCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
cmd := message.Payload.(*messages.BookFlightsCmd)
invocation.Log().Infof("booking flight to %s", cmd.Destination)
reply := gbus.NewBusMessage(messages.BookFlightsRsp{
Success: true,
})
invocation.Reply(invocation.Ctx(), reply)

return nil
}

func HandleCancelFlightCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
cmd := message.Payload.(*messages.CancelFlightsCmd)
invocation.Log().Infof("canceling flight to %s", cmd.Destination)
reply := gbus.NewBusMessage(messages.CancelFlightsRsp{
Success: true,
})
invocation.Reply(invocation.Ctx(), reply)

return nil
}
17 changes: 17 additions & 0 deletions examples/vacation_app/cmd/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"github.com/wework/grabbit/gbus"
"github.com/wework/grabbit/gbus/builder"
)

func createBus(serviceName string) gbus.Bus {
return builder.
New().
Bus("amqp://rabbitmq:rabbitmq@localhost").
WorkerNum(3, 1).
WithConfirms().
PurgeOnStartUp().
Txnl("mysql", "rhinof:rhinof@/rhinof").
Build(serviceName)
}
56 changes: 56 additions & 0 deletions examples/vacation_app/cmd/hotels.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package cmd

import (
"bufio"
"fmt"
"os"
"strings"
"vacation_app/messages"
"vacation_app/trace"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/wework/grabbit/gbus"
)

var runHotelsgServiceCmd = &cobra.Command{
Use: "hotels",
Short: "Run the hotels service",
Run: func(cmd *cobra.Command, args []string) {
svcName := "hotels-service"
closer, err := trace.CreatetJeagerTracer(svcName)

if err != nil {
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
return
}

defer closer.Close()
gb := createBus(svcName)
gb.HandleMessage(messages.BookHotelCmd{}, HandleBookHotelCommand)
gb.Start()
defer gb.Shutdown()

fmt.Print("Hotels service running...press any key to exit...\n")
reader := bufio.NewReader(os.Stdin)
reader.ReadString('\n')
},
}

func HandleBookHotelCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
cmd := message.Payload.(*messages.BookHotelCmd)
destination := cmd.Destination
response := messages.BookHotelRsp{}

if strings.ToLower(destination) == "oslo" {
response.Success = false
invocation.Log().Info("can't book hotels in oslo at this time")
} else {
response.Success = true
invocation.Log().Infof("booking hotel to %s", cmd.Destination)
}

invocation.Reply(invocation.Ctx(), gbus.NewBusMessage(response))

return nil
}
30 changes: 30 additions & 0 deletions examples/vacation_app/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(runClientCmd, runBookingServiceeCmd, runFlightsgServiceCmd, runHotelsgServiceCmd)
}

var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
42 changes: 42 additions & 0 deletions examples/vacation_app/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
version: '3'

services:
rabbitmq:
image: "rabbitmq:3-management"
hostname: "rabbit1"
environment:
RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
RABBITMQ_DEFAULT_USER: "rabbitmq"
RABBITMQ_DEFAULT_PASS: "rabbitmq"
RABBITMQ_DEFAULT_VHOST: "/"
ports:
- "15672:15672"
- "5672:5672"
labels:
NAME: "rabbitmq1"

mysqldb:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_DATABASE: rhinof
MYSQL_ROOT_PASSWORD: rhinof
MYSQL_USER: rhinof
MYSQL_PASSWORD: rhinof
ports:
- 3306:3306
adminer:
image: adminer
ports:
- 8080:8080
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "5775:5775/udp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
- "16686:16686"
- "14268:14268"
- "9411:9411"
14 changes: 14 additions & 0 deletions examples/vacation_app/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module vacation_app

go 1.12

require (
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/opentracing/opentracing-go v1.1.0
github.com/rhinof/grabbit v0.0.0-20190411110638-a50e536d03e3
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/uber/jaeger-client-go v2.16.0+incompatible
github.com/uber/jaeger-lib v2.0.0+incompatible
github.com/wework/grabbit v1.1.5-0.20190929052249-0cd9890ac0f4
)
Loading

0 comments on commit 43af4d4

Please sign in to comment.