Skip to content

Commit 43af4d4

Browse files
author
Guy Baron
authored
Added sample application (#184)
1 parent 0cd9890 commit 43af4d4

17 files changed

+835
-0
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ the v1.x branch contains the latest stable releases of grabbit and one should tr
3333

3434
## Basic Usage
3535

36+
### See complete application in the examples/vacation_app folder
37+
3638
The following outlines the basic usage of grabbit.
3739
For a complete view of how you would use grabbit including how to write saga's and handle deadlettering refer to grabbit/tests package
3840

examples/vacation_app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vacation_app

examples/vacation_app/.gitingnore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vacation_app

examples/vacation_app/README.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## grabbit example vacation app
2+
3+
The following example simulates a vacation booking app and demonstrates the use of grabbit
4+
to manage the booking process.
5+
6+
The app is made up out of the following components
7+
8+
- The client, a console app that you enter your vacation destination and calls the booking service to
9+
book the vacation.
10+
11+
- 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.
12+
The booking saga sends back a message to the client with the result of the booking request once the saga completes.
13+
14+
- Flights Service, books flights to the requested destination and replies back the response.
15+
The flight service.
16+
17+
- Hotels Service, books hotels for the requested destination and replies back the response.
18+
In this example requesting to book a vacation in Oslo results in a reply message with a Failed status
19+
Triggering the booking saga to send a command to the flight service to cancel the booked flights.
20+
21+
## building and running the example
22+
23+
- go build
24+
- docker-compose up
25+
- run the booking servce: vacation_app booking
26+
- run the hotels servce: vacation_app hotels
27+
- run the flights servce: vacation_app flights
28+
- run the client: vacation_app client
29+
30+
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.
31+
32+
33+
You can see a trace of the calls by browsing to the Jeager client at http://localhost:16686
34+
35+

examples/vacation_app/cmd/booking.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"vacation_app/trace"
8+
9+
log "github.com/sirupsen/logrus"
10+
"github.com/spf13/cobra"
11+
"vacation_app/saga"
12+
)
13+
14+
func init() {
15+
rootCmd.AddCommand(runBookingServiceeCmd)
16+
}
17+
18+
var runBookingServiceeCmd = &cobra.Command{
19+
Use: "booking",
20+
Short: "Run the booking service",
21+
Run: func(cmd *cobra.Command, args []string) {
22+
svcName := "booking-service"
23+
closer, err := trace.CreatetJeagerTracer(svcName)
24+
25+
if err != nil {
26+
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
27+
return
28+
}
29+
30+
defer closer.Close()
31+
gb := createBus(svcName)
32+
33+
gb.RegisterSaga(&saga.BookingSaga{})
34+
gb.Start()
35+
defer gb.Shutdown()
36+
37+
fmt.Print("Booking service running...press any key to exit...\n")
38+
reader := bufio.NewReader(os.Stdin)
39+
reader.ReadString('\n')
40+
},
41+
}

examples/vacation_app/cmd/client.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"context"
6+
"fmt"
7+
"os"
8+
"strings"
9+
"vacation_app/messages"
10+
"vacation_app/trace"
11+
12+
log "github.com/sirupsen/logrus"
13+
"github.com/spf13/cobra"
14+
"github.com/wework/grabbit/gbus"
15+
)
16+
17+
18+
var runClientCmd = &cobra.Command{
19+
Use: "client",
20+
Short: "Run the client app",
21+
Run: func(cmd *cobra.Command, args []string) {
22+
fmt.Println("\033]0;Title goes here\007")
23+
log.SetFormatter(&log.TextFormatter{ForceColors: true})
24+
log.SetLevel(log.ErrorLevel)
25+
26+
svcName := "client"
27+
closer, err := trace.CreatetJeagerTracer(svcName)
28+
29+
if err != nil {
30+
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
31+
return
32+
}
33+
defer closer.Close()
34+
gb := createBus(svcName)
35+
36+
gb.HandleMessage(messages.BookingComplete{}, HandleBookingComplete)
37+
gb.Start()
38+
defer gb.Shutdown()
39+
40+
for {
41+
fmt.Print("Enter destination ...\n")
42+
reader := bufio.NewReader(os.Stdin)
43+
dest, _ := reader.ReadString('\n')
44+
dest = strings.TrimSpace(dest)
45+
bookVacationCmd := gbus.NewBusMessage(messages.BookVacationCmd{
46+
Destination: dest,
47+
})
48+
49+
gb.Send(context.Background(), "booking-service", bookVacationCmd)
50+
51+
fmt.Printf("booking vacation for destination %s\n", dest)
52+
53+
}
54+
},
55+
}
56+
57+
func HandleBookingComplete(invocation gbus.Invocation, message *gbus.BusMessage) error {
58+
bookingComplete := message.Payload.(*messages.BookingComplete)
59+
if bookingComplete.Success {
60+
fmt.Printf("booking completed succesfully\n")
61+
62+
} else {
63+
fmt.Printf("failed to book vacation\n")
64+
}
65+
return nil
66+
}

examples/vacation_app/cmd/flights.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"vacation_app/trace"
8+
"vacation_app/messages"
9+
10+
log "github.com/sirupsen/logrus"
11+
"github.com/spf13/cobra"
12+
"github.com/wework/grabbit/gbus"
13+
)
14+
15+
16+
17+
var runFlightsgServiceCmd = &cobra.Command{
18+
Use: "flights",
19+
Short: "Run the flights service",
20+
Run: func(cmd *cobra.Command, args []string) {
21+
svcName := "flights-service"
22+
closer, err := trace.CreatetJeagerTracer(svcName)
23+
24+
if err != nil {
25+
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
26+
return
27+
}
28+
29+
defer closer.Close()
30+
gb := createBus(svcName)
31+
32+
gb.HandleMessage(messages.BookFlightsCmd{}, HandleBookFlightCommand)
33+
gb.HandleMessage(messages.CancelFlightsCmd{}, HandleCancelFlightCommand)
34+
35+
gb.Start()
36+
defer gb.Shutdown()
37+
38+
fmt.Print("Flights service running...press any key to exit...\n")
39+
reader := bufio.NewReader(os.Stdin)
40+
reader.ReadString('\n')
41+
},
42+
}
43+
44+
func HandleBookFlightCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
45+
cmd := message.Payload.(*messages.BookFlightsCmd)
46+
invocation.Log().Infof("booking flight to %s", cmd.Destination)
47+
reply := gbus.NewBusMessage(messages.BookFlightsRsp{
48+
Success: true,
49+
})
50+
invocation.Reply(invocation.Ctx(), reply)
51+
52+
return nil
53+
}
54+
55+
func HandleCancelFlightCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
56+
cmd := message.Payload.(*messages.CancelFlightsCmd)
57+
invocation.Log().Infof("canceling flight to %s", cmd.Destination)
58+
reply := gbus.NewBusMessage(messages.CancelFlightsRsp{
59+
Success: true,
60+
})
61+
invocation.Reply(invocation.Ctx(), reply)
62+
63+
return nil
64+
}

examples/vacation_app/cmd/helper.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cmd
2+
3+
import (
4+
"github.com/wework/grabbit/gbus"
5+
"github.com/wework/grabbit/gbus/builder"
6+
)
7+
8+
func createBus(serviceName string) gbus.Bus {
9+
return builder.
10+
New().
11+
Bus("amqp://rabbitmq:rabbitmq@localhost").
12+
WorkerNum(3, 1).
13+
WithConfirms().
14+
PurgeOnStartUp().
15+
Txnl("mysql", "rhinof:rhinof@/rhinof").
16+
Build(serviceName)
17+
}

examples/vacation_app/cmd/hotels.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"strings"
8+
"vacation_app/messages"
9+
"vacation_app/trace"
10+
11+
log "github.com/sirupsen/logrus"
12+
"github.com/spf13/cobra"
13+
"github.com/wework/grabbit/gbus"
14+
)
15+
16+
var runHotelsgServiceCmd = &cobra.Command{
17+
Use: "hotels",
18+
Short: "Run the hotels service",
19+
Run: func(cmd *cobra.Command, args []string) {
20+
svcName := "hotels-service"
21+
closer, err := trace.CreatetJeagerTracer(svcName)
22+
23+
if err != nil {
24+
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
25+
return
26+
}
27+
28+
defer closer.Close()
29+
gb := createBus(svcName)
30+
gb.HandleMessage(messages.BookHotelCmd{}, HandleBookHotelCommand)
31+
gb.Start()
32+
defer gb.Shutdown()
33+
34+
fmt.Print("Hotels service running...press any key to exit...\n")
35+
reader := bufio.NewReader(os.Stdin)
36+
reader.ReadString('\n')
37+
},
38+
}
39+
40+
func HandleBookHotelCommand(invocation gbus.Invocation, message *gbus.BusMessage) error {
41+
cmd := message.Payload.(*messages.BookHotelCmd)
42+
destination := cmd.Destination
43+
response := messages.BookHotelRsp{}
44+
45+
if strings.ToLower(destination) == "oslo" {
46+
response.Success = false
47+
invocation.Log().Info("can't book hotels in oslo at this time")
48+
} else {
49+
response.Success = true
50+
invocation.Log().Infof("booking hotel to %s", cmd.Destination)
51+
}
52+
53+
invocation.Reply(invocation.Ctx(), gbus.NewBusMessage(response))
54+
55+
return nil
56+
}

examples/vacation_app/cmd/root.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func init() {
11+
rootCmd.AddCommand(runClientCmd, runBookingServiceeCmd, runFlightsgServiceCmd, runHotelsgServiceCmd)
12+
}
13+
14+
var rootCmd = &cobra.Command{
15+
Use: "hugo",
16+
Short: "Hugo is a very fast static site generator",
17+
Long: `A Fast and Flexible Static Site Generator built with
18+
love by spf13 and friends in Go.
19+
Complete documentation is available at http://hugo.spf13.com`,
20+
Run: func(cmd *cobra.Command, args []string) {
21+
// Do Stuff Here
22+
},
23+
}
24+
25+
func Execute() {
26+
if err := rootCmd.Execute(); err != nil {
27+
fmt.Println(err)
28+
os.Exit(1)
29+
}
30+
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
version: '3'
2+
3+
services:
4+
rabbitmq:
5+
image: "rabbitmq:3-management"
6+
hostname: "rabbit1"
7+
environment:
8+
RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
9+
RABBITMQ_DEFAULT_USER: "rabbitmq"
10+
RABBITMQ_DEFAULT_PASS: "rabbitmq"
11+
RABBITMQ_DEFAULT_VHOST: "/"
12+
ports:
13+
- "15672:15672"
14+
- "5672:5672"
15+
labels:
16+
NAME: "rabbitmq1"
17+
18+
mysqldb:
19+
image: mysql
20+
command: --default-authentication-plugin=mysql_native_password
21+
restart: always
22+
environment:
23+
MYSQL_DATABASE: rhinof
24+
MYSQL_ROOT_PASSWORD: rhinof
25+
MYSQL_USER: rhinof
26+
MYSQL_PASSWORD: rhinof
27+
ports:
28+
- 3306:3306
29+
adminer:
30+
image: adminer
31+
ports:
32+
- 8080:8080
33+
jaeger:
34+
image: jaegertracing/all-in-one:latest
35+
ports:
36+
- "5775:5775/udp"
37+
- "6831:6831/udp"
38+
- "6832:6832/udp"
39+
- "5778:5778"
40+
- "16686:16686"
41+
- "14268:14268"
42+
- "9411:9411"

examples/vacation_app/go.mod

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module vacation_app
2+
3+
go 1.12
4+
5+
require (
6+
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
7+
github.com/opentracing/opentracing-go v1.1.0
8+
github.com/rhinof/grabbit v0.0.0-20190411110638-a50e536d03e3
9+
github.com/sirupsen/logrus v1.4.2
10+
github.com/spf13/cobra v0.0.5
11+
github.com/uber/jaeger-client-go v2.16.0+incompatible
12+
github.com/uber/jaeger-lib v2.0.0+incompatible
13+
github.com/wework/grabbit v1.1.5-0.20190929052249-0cd9890ac0f4
14+
)

0 commit comments

Comments
 (0)