bunny

package module
v0.0.0-...-3262849 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 26, 2019 License: BSD-3-Clause Imports: 14 Imported by: 0

README

Bunny

A cute library to write asynchronous microservices in Go

Requirements

This library requires Go 1.12 and Git

Quick Start

Create a new service

package main

import (
	"context"
	"github.com/sirupsen/logrus"
	"gitlab.com/venini42/bunny"
	bunnyctx "gitlab.com/venini42/bunny/pkg/context"
	"gitlab.com/venini42/bunny/pkg/rabbitmq"
	"os"
)

func main() {
	logger := logrus.New()

    // Create a new service instance
	service, err := bunny.NewService(
		bunny.ServiceName("example"),
		bunny.ServiceLogger(logger),
	)
	if err != nil {
		panic(err)
	}

    // Add a listener
	service.AddListener("example", "example", func(ctx context.Context, delivery rabbitmq.Delivery, _ rabbitmq.ReplyFunc) error {
		service.Logger.Infof("Received message on topic %s: %s", "example", string(body))
		return nil
	})

    // Start the service. This is blocking until
    // a fatal error occurs or a SIGTERM is notified
	err = service.Start()
	if err != nil {
		panic(err)
	}

	os.Exit(0)
}

Listeners

Listeners are basically like controllers in a traditional HTTP application. The handle a request that has a body, some headers, and may generate a response. Note that unlike HTTP controllers, Bunny listeners are not required to return a response.
They can use the reply function if the message is part of a request/response cycle or an RPC API.
See Context

Async listeners

A listener can be completely asynchronous. This is useful when subscribing to application events.
For example, let's update a search index when a new user is created:

service.AddListener("users", "users:created", func(ctx context.Context, body []byte, _ rabbitmq.ReplyFunc) error {
    user := deserialize(body) // unmarshal the body into a struct 
    service.Logger.Infof("Updating search index for user id: %s", user.Id)
    
    return search.UpdateIndex("users", user) // example code 
})
RPC Listeners

A service often needs to reply to the caller and complete a request/response cycle.
A convenient reply function is provided:

service.AddListener("users", "users:get-all", func(ctx context.Context, request rabbitmq.Delivery, reply rabbitmq.ReplyFunc) error {
    users := db.GetAllUsers() 
    service.Logger.Infof("Found %d users", len(users))
    
    body := serialize(users)
    response := rabbitmq.Response {
        Body: body    
    }   
    return reply(ctx, response) 
})
Context

A context.Context object is provided to every listener function.

Among other things, it contains some useful information about the current request. At the moment it contains the following:

  • the request CorrelationId. This should be propagated to all the involved microservices that are invoked as part of the same request.
  • The request ReplyTo param. Note that this is an empty string ("") if not set.

This information can be easily accessed using the gitlab.com/venini42/bunny/pkg/context package:

import (
    "context"
    bunnyctx "gitlab.com/venini42/bunny/pkg/context"
)

ctx := context.Background()

ctx = bunnyctx.WithCorrelationId(ctx, "some-uuid")
ctx = bunnyctx.WithReplyTo(ctx, "reply-here")

correlationId := bunnyctx.GetCorrelationId(ctx)
replyTo := bunnyctx.GetReplyTo(ctx)

Calling other services

Much like a service can have both async and RPC handlers, it can also invoke other services responding the same way.

// Send an async message on the given exchange with the given routing
// or topic. It's basically fire-and-forget
service.Rabbit.Cast(ctx context.Context, request rabbitmq.Delivery) error

// Send a "sync" message, waiting for the response to come back and returning it.
// It leverages RabbitMQ's Direct ReplyTo feature to avoid creating temporary
// response queues, making it very lightweight
service.Rabbit.Call(ctx context.Context, request rabbitmq.Delivery) (Response, error) {

More information about Rabbit's Direct ReplyTo can be found here.

Tracing

TBD

Configuration

TBD

Examples

The example folder contains a client and a service that showcase both an async request and a RPC call with a reply

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Service

type Service struct {
	Name,
	BrokerUrl string
	Rabbit rabbitmq.Client
	Logger logrus.FieldLogger
	Cache  cache.Store
	// contains filtered or unexported fields
}

func NewService

func NewService(opts ...ServiceOption) (*Service, error)

func (*Service) AddListener

func (s *Service) AddListener(exchange, topic string, handler rabbitmq.MessageHandler)

func (*Service) Start

func (s *Service) Start() error

type ServiceOption

type ServiceOption func(opts *ServiceOptions)

func ServiceBrokerUrl

func ServiceBrokerUrl(url string) ServiceOption

func ServiceCache

func ServiceCache(cache cache.Store) ServiceOption

func ServiceHealthCheckPort

func ServiceHealthCheckPort(port int) ServiceOption

func ServiceLogger

func ServiceLogger(logger logrus.FieldLogger) ServiceOption

func ServiceName

func ServiceName(name string) ServiceOption

func ServiceTimeout

func ServiceTimeout(seconds int) ServiceOption

type ServiceOptions

type ServiceOptions struct {
	// contains filtered or unexported fields
}

Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL