commit
097395c5cb
47
README.md
47
README.md
@ -20,14 +20,15 @@ Go Micro abstracts way the details of distributed systems. Here are the main fea
|
||||
- **Message Encoding** - Micro services can encode requests in a number of encoding formats and seamlessly decode based on the Content-Type header.
|
||||
- **RPC Client/Server** - The client and server leverage the above features and provide a clean simple interface for building microservices.
|
||||
|
||||
Go Micro supports both the Service and Function programming models. Read on to learn more.
|
||||
|
||||
## Docs
|
||||
|
||||
For more detailed information on the architecture, installation and use of go-micro checkout the [docs](https://micro.mu/docs).
|
||||
|
||||
## Learn By Example
|
||||
|
||||
An example service can be found in [**examples/service**](https://github.com/micro/examples/tree/master/service). The [**examples**](https://github.com/micro/examples) directory contains many more examples for using things such as middleware/wrappers, selector filters, pub/sub and code generation.
|
||||
|
||||
An example service can be found in [**examples/service**](https://github.com/micro/examples/tree/master/service) and function in [**examples/function**](https://github.com/micro/examples/tree/master/function). The [**examples**](https://github.com/micro/examples) directory contains many more examples for using things such as middleware/wrappers, selector filters, pub/sub and code generation.
|
||||
For the complete greeter example look at [**examples/greeter**](https://github.com/micro/examples/tree/master/greeter). Other examples can be found throughout the GitHub repository.
|
||||
|
||||
Check out the blog post to learn how to write go-micro services [https://micro.mu/blog/2016/03/28/go-micro.html](https://micro.mu/blog/2016/03/28/go-micro.html) or watch the talk from the [Golang UK Conf 2016](https://www.youtube.com/watch?v=xspaDovwk34).
|
||||
@ -228,6 +229,48 @@ go run client.go
|
||||
Hello John
|
||||
```
|
||||
|
||||
## Writing a Function
|
||||
|
||||
Go Micro includes the Function programming model. This is the notion of a one time executing Service which operates much like a service except exiting
|
||||
after completing a request. A function is defined much like a service and called in exactly the same way.
|
||||
|
||||
### Defining a Function
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
proto "github.com/micro/examples/function/proto"
|
||||
"github.com/micro/go-micro"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Greeter struct{}
|
||||
|
||||
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
|
||||
rsp.Greeting = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// create a new function
|
||||
fnc := micro.NewFunction(
|
||||
micro.Name("go.micro.fnc.greeter"),
|
||||
)
|
||||
|
||||
// init the command line
|
||||
fnc.Init()
|
||||
|
||||
// register a handler
|
||||
fnc.Handle(new(Greeter))
|
||||
|
||||
// run the function
|
||||
fnc.Run()
|
||||
}
|
||||
```
|
||||
|
||||
It's that simple.
|
||||
|
||||
## How does it work?
|
||||
|
||||
<p align="center">
|
||||
|
81
function.go
Normal file
81
function.go
Normal file
@ -0,0 +1,81 @@
|
||||
package micro
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/server"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type function struct {
|
||||
cancel context.CancelFunc
|
||||
Service
|
||||
}
|
||||
|
||||
func fnHandlerWrapper(f Function) server.HandlerWrapper {
|
||||
return func(h server.HandlerFunc) server.HandlerFunc {
|
||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
defer f.Done()
|
||||
return h(ctx, req, rsp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fnSubWrapper(f Function) server.SubscriberWrapper {
|
||||
return func(s server.SubscriberFunc) server.SubscriberFunc {
|
||||
return func(ctx context.Context, msg server.Publication) error {
|
||||
defer f.Done()
|
||||
return s(ctx, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newFunction(opts ...Option) Function {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// force ttl/interval
|
||||
fopts := []Option{
|
||||
RegisterTTL(time.Minute),
|
||||
RegisterInterval(time.Second * 30),
|
||||
}
|
||||
|
||||
// prepend to opts
|
||||
fopts = append(fopts, opts...)
|
||||
|
||||
// make context the last thing
|
||||
fopts = append(fopts, Context(ctx))
|
||||
|
||||
service := newService(fopts...)
|
||||
|
||||
fn := &function{
|
||||
cancel: cancel,
|
||||
Service: service,
|
||||
}
|
||||
|
||||
service.Server().Init(
|
||||
// ensure the service waits for requests to finish
|
||||
server.Wait(true),
|
||||
// wrap handlers and subscribers to finish execution
|
||||
server.WrapHandler(fnHandlerWrapper(fn)),
|
||||
server.WrapSubscriber(fnSubWrapper(fn)),
|
||||
)
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
func (f *function) Done() error {
|
||||
f.cancel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *function) Handle(v interface{}) error {
|
||||
return f.Service.Server().Handle(
|
||||
f.Service.Server().NewHandler(v),
|
||||
)
|
||||
}
|
||||
|
||||
func (f *function) Subscribe(topic string, v interface{}) error {
|
||||
return f.Service.Server().Subscribe(
|
||||
f.Service.Server().NewSubscriber(topic, v),
|
||||
)
|
||||
}
|
55
function_test.go
Normal file
55
function_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
package micro
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/registry/mock"
|
||||
proto "github.com/micro/go-micro/server/debug/proto"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestFunction(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
// create service
|
||||
fn := NewFunction(
|
||||
Name("test.function"),
|
||||
Registry(mock.NewRegistry()),
|
||||
AfterStart(func() error {
|
||||
wg.Done()
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
|
||||
// we can't test fn.Init as it parses the command line
|
||||
// fn.Init()
|
||||
|
||||
go func() {
|
||||
// wait for start
|
||||
wg.Wait()
|
||||
|
||||
// test call debug
|
||||
req := fn.Client().NewRequest(
|
||||
"test.function",
|
||||
"Debug.Health",
|
||||
new(proto.HealthRequest),
|
||||
)
|
||||
|
||||
rsp := new(proto.HealthResponse)
|
||||
|
||||
err := fn.Client().Call(context.TODO(), req, rsp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if rsp.Status != "ok" {
|
||||
t.Fatalf("function response: %s", rsp.Status)
|
||||
}
|
||||
}()
|
||||
|
||||
// run service
|
||||
fn.Run()
|
||||
}
|
17
go-micro.go
17
go-micro.go
@ -22,6 +22,18 @@ type Service interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Function is a one time executing Service
|
||||
type Function interface {
|
||||
// Inherits Service interface
|
||||
Service
|
||||
// Done signals to complete execution
|
||||
Done() error
|
||||
// Handle registers an RPC handler
|
||||
Handle(v interface{}) error
|
||||
// Subscribe registers a subscriber
|
||||
Subscribe(topic string, v interface{}) error
|
||||
}
|
||||
|
||||
// Publisher is syntactic sugar for publishing
|
||||
type Publisher interface {
|
||||
Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error
|
||||
@ -49,6 +61,11 @@ func NewContext(ctx context.Context, s Service) context.Context {
|
||||
return context.WithValue(ctx, serviceKey{}, s)
|
||||
}
|
||||
|
||||
// NewFunction returns a new Function for a one time executing Service
|
||||
func NewFunction(opts ...Option) Function {
|
||||
return newFunction(opts...)
|
||||
}
|
||||
|
||||
// NewPublisher returns a new Publisher
|
||||
func NewPublisher(topic string, c client.Client) Publisher {
|
||||
if c == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user