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. | - **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. | - **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 | ## Docs | ||||||
|  |  | ||||||
| For more detailed information on the architecture, installation and use of go-micro checkout the [docs](https://micro.mu/docs). | For more detailed information on the architecture, installation and use of go-micro checkout the [docs](https://micro.mu/docs). | ||||||
|  |  | ||||||
| ## Learn By Example | ## 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. | 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). | 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 | 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? | ## How does it work? | ||||||
|  |  | ||||||
| <p align="center"> | <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 | 	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 | // Publisher is syntactic sugar for publishing | ||||||
| type Publisher interface { | type Publisher interface { | ||||||
| 	Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error | 	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) | 	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 | // NewPublisher returns a new Publisher | ||||||
| func NewPublisher(topic string, c client.Client) Publisher { | func NewPublisher(topic string, c client.Client) Publisher { | ||||||
| 	if c == nil { | 	if c == nil { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user