diff --git a/component.go b/component.go index ca5fd054b..c9131f8b6 100644 --- a/component.go +++ b/component.go @@ -15,7 +15,6 @@ package weaver import ( - "context" "crypto/tls" "net" "sync" @@ -101,13 +100,7 @@ type component struct { var _ Instance = &componentImpl{} // Main is interface implemented by an application's main component. -// This component is instantiated and its Main() method called by -// `weaver.Run`. -type Main interface { - // Main contains the application main. It typically loops - // forever, e.g., inside http.Serve. - Main(context.Context) error -} +type Main interface{} // Implements[T] is a type that can be embedded inside a component implementation // struct to indicate that the struct implements a component of type T. E.g., diff --git a/examples/chat/main.go b/examples/chat/main.go index 53fac5801..7a62ac0ec 100644 --- a/examples/chat/main.go +++ b/examples/chat/main.go @@ -26,7 +26,7 @@ import ( func main() { flag.Parse() - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } diff --git a/examples/chat/server.go b/examples/chat/server.go index 7bcc96ba1..c38d059e2 100644 --- a/examples/chat/server.go +++ b/examples/chat/server.go @@ -43,7 +43,7 @@ type server struct { chat weaver.Listener } -func (s *server) Main(ctx context.Context) error { +func serve(ctx context.Context, s *server) error { s.httpServer.Handler = instrument(s.label, s) s.Logger().Debug("Chat service available", "address", s.chat) return s.httpServer.Serve(s.chat) diff --git a/examples/chat/weaver_gen.go b/examples/chat/weaver_gen.go index a2ef6b159..ded544e8c 100644 --- a/examples/chat/weaver_gen.go +++ b/examples/chat/weaver_gen.go @@ -54,9 +54,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -168,23 +166,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - type sQLStore_local_stub struct { impl SQLStore tracer trace.Tracer @@ -457,61 +438,12 @@ func (s localCache_client_stub) Put(ctx context.Context, a0 string, a1 string) ( } type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - type sQLStore_client_stub struct { stub codegen.Stub createPostMetrics *codegen.MethodMetrics @@ -880,32 +812,11 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} - type sQLStore_server_stub struct { impl SQLStore addLoad func(key uint64, load float64) diff --git a/examples/collatz/main.go b/examples/collatz/main.go index fe0cfe517..9a3f940ab 100644 --- a/examples/collatz/main.go +++ b/examples/collatz/main.go @@ -59,7 +59,7 @@ var localAddr = flag.String("local_addr", "localhost:9000", "Collatz server loca func main() { flag.Parse() - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } diff --git a/examples/collatz/server.go b/examples/collatz/server.go index 77bd9cf2c..2876d3cda 100644 --- a/examples/collatz/server.go +++ b/examples/collatz/server.go @@ -33,7 +33,7 @@ type server struct { lis weaver.Listener `weaver:"collatz"` } -func (s *server) Main(ctx context.Context) error { +func serve(ctx context.Context, s *server) error { s.mux.Handle("/", weaver.InstrumentHandlerFunc("collatz", s.handle)) s.mux.HandleFunc(weaver.HealthzURL, weaver.HealthzHandler) s.Logger().Debug("Collatz service available", "address", s.lis) diff --git a/examples/collatz/weaver_gen.go b/examples/collatz/weaver_gen.go index f652a2432..88688edc9 100644 --- a/examples/collatz/weaver_gen.go +++ b/examples/collatz/weaver_gen.go @@ -36,9 +36,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -104,23 +102,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - type odd_local_stub struct { impl Odd tracer trace.Tracer @@ -214,61 +195,12 @@ func (s even_client_stub) Do(ctx context.Context, a0 int) (r0 int, err error) { } type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - type odd_client_stub struct { stub codegen.Stub doMetrics *codegen.MethodMetrics @@ -390,32 +322,11 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} - type odd_server_stub struct { impl Odd addLoad func(key uint64, load float64) diff --git a/examples/factors/main.go b/examples/factors/main.go index f95642629..d4dc37adc 100644 --- a/examples/factors/main.go +++ b/examples/factors/main.go @@ -28,7 +28,7 @@ import ( func main() { flag.Parse() ctx := context.Background() - if err := weaver.Run(ctx); err != nil { + if err := weaver.Run(ctx, serve); err != nil { log.Fatal(err) } } diff --git a/examples/factors/server.go b/examples/factors/server.go index 2ef52e298..bf4604747 100644 --- a/examples/factors/server.go +++ b/examples/factors/server.go @@ -29,7 +29,7 @@ type server struct { lis weaver.Listener `weaver:"factors"` } -func (s *server) Main(ctx context.Context) error { +func serve(ctx context.Context, s *server) error { http.Handle("/", weaver.InstrumentHandlerFunc("/", s.handleFactors)) s.Logger().Info("factors server running", "addr", s.lis) return http.Serve(s.lis, nil) diff --git a/examples/factors/weaver_gen.go b/examples/factors/weaver_gen.go index 0e5065499..a80cc6ee7 100644 --- a/examples/factors/weaver_gen.go +++ b/examples/factors/weaver_gen.go @@ -39,9 +39,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -95,23 +93,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - // Client stub implementations. type factorer_client_stub struct { @@ -183,61 +164,12 @@ func (s factorer_client_stub) Factors(ctx context.Context, a0 int) (r0 []int, er } type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - // Server stub implementations. type factorer_server_stub struct { @@ -296,32 +228,11 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} - // Router methods. // _hashFactorer returns a 64 bit hash of the provided value. diff --git a/examples/hello/main.go b/examples/hello/main.go index 1b58b6ee6..5d09bf362 100644 --- a/examples/hello/main.go +++ b/examples/hello/main.go @@ -23,7 +23,7 @@ import ( ) func main() { - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } @@ -36,7 +36,7 @@ type app struct { hello weaver.Listener } -func (app *app) Main(ctx context.Context) error { +func serve(ctx context.Context, app *app) error { fmt.Printf("hello listener available on %v\n", app.hello) // Serve the /hello endpoint. diff --git a/examples/hello/weaver_gen.go b/examples/hello/weaver_gen.go index f25fa2323..0d1b7912a 100644 --- a/examples/hello/weaver_gen.go +++ b/examples/hello/weaver_gen.go @@ -23,9 +23,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -66,23 +64,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - type reverser_local_stub struct { impl Reverser tracer trace.Tracer @@ -111,61 +92,12 @@ func (s reverser_local_stub) Reverse(ctx context.Context, a0 string) (r0 string, // Client stub implementations. type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - type reverser_client_stub struct { stub codegen.Stub reverseMetrics *codegen.MethodMetrics @@ -244,32 +176,11 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} - type reverser_server_stub struct { impl Reverser addLoad func(key uint64, load float64) diff --git a/examples/onlineboutique/frontend/frontend.go b/examples/onlineboutique/frontend/frontend.go index 156ef9a51..e30fc47f3 100644 --- a/examples/onlineboutique/frontend/frontend.go +++ b/examples/onlineboutique/frontend/frontend.go @@ -88,7 +88,7 @@ type Server struct { boutique weaver.Listener } -func (s *Server) Main(ctx context.Context) error { +func Serve(ctx context.Context, s *Server) error { // Find out where we're running. // Set ENV_PLATFORM (default to local if not set; use env var if set; // otherwise detect GCP, which overrides env). diff --git a/examples/onlineboutique/frontend/weaver_gen.go b/examples/onlineboutique/frontend/weaver_gen.go index 13b5dd826..572a7a5eb 100644 --- a/examples/onlineboutique/frontend/weaver_gen.go +++ b/examples/onlineboutique/frontend/weaver_gen.go @@ -5,13 +5,10 @@ package frontend // Code generated by "weaver generate". DO NOT EDIT. import ( "context" - "errors" "github.com/ServiceWeaver/weaver" "github.com/ServiceWeaver/weaver/runtime/codegen" - "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "reflect" - "time" ) var _ codegen.LatestVersion = codegen.Version[[0][11]struct{}]("You used 'weaver generate' codegen version 0.11.0, but you built your code with an incompatible weaver module version. Try upgrading 'weaver generate' and re-running it.") @@ -23,9 +20,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -49,81 +44,15 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "frontend.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - // Client stub implementations. type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "frontend.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - // Server stub implementations. type main_server_stub struct { @@ -137,28 +66,7 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } - -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} diff --git a/examples/onlineboutique/main.go b/examples/onlineboutique/main.go index aeebcc561..f71b02318 100644 --- a/examples/onlineboutique/main.go +++ b/examples/onlineboutique/main.go @@ -29,14 +29,14 @@ import ( "log" "github.com/ServiceWeaver/weaver" - _ "github.com/ServiceWeaver/weaver/examples/onlineboutique/frontend" + "github.com/ServiceWeaver/weaver/examples/onlineboutique/frontend" ) //go:generate ../../cmd/weaver/weaver generate ./... func main() { flag.Parse() - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), frontend.Serve); err != nil { log.Fatal(err) } } diff --git a/examples/reverser/main.go b/examples/reverser/main.go index 4ddc501b8..12dc4db85 100644 --- a/examples/reverser/main.go +++ b/examples/reverser/main.go @@ -37,7 +37,7 @@ var ( func main() { // Initialize the Service Weaver application. flag.Parse() - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } @@ -48,7 +48,7 @@ type server struct { lis weaver.Listener `weaver:"reverser"` } -func (s *server) Main(ctx context.Context) error { +func serve(ctx context.Context, s *server) error { // Setup the HTTP handler. var mux http.ServeMux mux.Handle("/", weaver.InstrumentHandlerFunc("reverser", diff --git a/examples/reverser/weaver_gen.go b/examples/reverser/weaver_gen.go index 059dec829..18e5228f1 100644 --- a/examples/reverser/weaver_gen.go +++ b/examples/reverser/weaver_gen.go @@ -23,9 +23,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -66,23 +64,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - type reverser_local_stub struct { impl Reverser tracer trace.Tracer @@ -111,61 +92,12 @@ func (s reverser_local_stub) Reverse(ctx context.Context, a0 string) (r0 string, // Client stub implementations. type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - type reverser_client_stub struct { stub codegen.Stub reverseMetrics *codegen.MethodMetrics @@ -244,32 +176,11 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} - type reverser_server_stub struct { impl Reverser addLoad func(key uint64, load float64) diff --git a/godeps.txt b/godeps.txt index b8545495a..c5a3617fa 100644 --- a/godeps.txt +++ b/godeps.txt @@ -260,7 +260,6 @@ github.com/ServiceWeaver/weaver/examples/onlineboutique/frontend github.com/ServiceWeaver/weaver/runtime/codegen github.com/google/uuid go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp - go.opentelemetry.io/otel/codes go.opentelemetry.io/otel/trace golang.org/x/exp/slog html/template @@ -730,13 +729,10 @@ github.com/ServiceWeaver/weaver/runtime/bin os github.com/ServiceWeaver/weaver/runtime/bin/testprogram context - errors github.com/ServiceWeaver/weaver github.com/ServiceWeaver/weaver/runtime/codegen - go.opentelemetry.io/otel/codes go.opentelemetry.io/otel/trace reflect - time github.com/ServiceWeaver/weaver/runtime/codegen bytes context @@ -916,13 +912,10 @@ github.com/ServiceWeaver/weaver/runtime/version strconv github.com/ServiceWeaver/weaver/runtime/version/testprogram context - errors github.com/ServiceWeaver/weaver github.com/ServiceWeaver/weaver/runtime/codegen - go.opentelemetry.io/otel/codes go.opentelemetry.io/otel/trace reflect - time github.com/ServiceWeaver/weaver/weavertest context errors diff --git a/internal/private/private.go b/internal/private/private.go index df19c8ebf..6a47fc1fa 100644 --- a/internal/private/private.go +++ b/internal/private/private.go @@ -32,14 +32,10 @@ type AppOptions struct { } // Starts starts a Service Weaver application. -// Callers are required to call app.Wait(). var Start func(ctx context.Context, options AppOptions) (App, error) // App is an internal handle to a Service Weaver application. type App interface { - // Wait returns when the application has ended. - Wait(context.Context) error - // Get fetches the component with interface type t from wlet. Get(requester string, t reflect.Type) (any, error) diff --git a/runtime/bin/testprogram/weaver_gen.go b/runtime/bin/testprogram/weaver_gen.go index 419ae47a9..09f5c8a7e 100644 --- a/runtime/bin/testprogram/weaver_gen.go +++ b/runtime/bin/testprogram/weaver_gen.go @@ -5,13 +5,10 @@ package main // Code generated by "weaver generate". DO NOT EDIT. import ( "context" - "errors" "github.com/ServiceWeaver/weaver" "github.com/ServiceWeaver/weaver/runtime/codegen" - "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "reflect" - "time" ) var _ codegen.LatestVersion = codegen.Version[[0][11]struct{}]("You used 'weaver generate' codegen version 0.11.0, but you built your code with an incompatible weaver module version. Try upgrading 'weaver generate' and re-running it.") @@ -56,9 +53,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -112,23 +107,6 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - // Client stub implementations. type a_client_stub struct { @@ -153,61 +131,12 @@ type c_client_stub struct { var _ C = (*c_client_stub)(nil) type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - // Server stub implementations. type a_server_stub struct { @@ -269,28 +198,7 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } - -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} diff --git a/runtime/version/testprogram/weaver_gen.go b/runtime/version/testprogram/weaver_gen.go index 066e6ed41..ebf0d895e 100644 --- a/runtime/version/testprogram/weaver_gen.go +++ b/runtime/version/testprogram/weaver_gen.go @@ -5,13 +5,10 @@ package main // Code generated by "weaver generate". DO NOT EDIT. import ( "context" - "errors" "github.com/ServiceWeaver/weaver" "github.com/ServiceWeaver/weaver/runtime/codegen" - "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "reflect" - "time" ) var _ codegen.LatestVersion = codegen.Version[[0][11]struct{}]("You used 'weaver generate' codegen version 0.11.0, but you built your code with an incompatible weaver module version. Try upgrading 'weaver generate' and re-running it.") @@ -23,9 +20,7 @@ func init() { LocalStubFn: func(impl any, tracer trace.Tracer) any { return main_local_stub{impl: impl.(weaver.Main), tracer: tracer} }, - ClientStubFn: func(stub codegen.Stub, caller string) any { - return main_client_stub{stub: stub, mainMetrics: codegen.MethodMetricsFor(codegen.MethodLabels{Caller: caller, Component: "github.com/ServiceWeaver/weaver/Main", Method: "Main"})} - }, + ClientStubFn: func(stub codegen.Stub, caller string) any { return main_client_stub{stub: stub} }, ServerStubFn: func(impl any, addLoad func(uint64, float64)) codegen.Server { return main_server_stub{impl: impl.(weaver.Main), addLoad: addLoad} }, @@ -49,81 +44,15 @@ type main_local_stub struct { // Check that main_local_stub implements the weaver.Main interface. var _ weaver.Main = (*main_local_stub)(nil) -func (s main_local_stub) Main(ctx context.Context) (err error) { - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.tracer.Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindInternal)) - defer func() { - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - } - span.End() - }() - } - - return s.impl.Main(ctx) -} - // Client stub implementations. type main_client_stub struct { - stub codegen.Stub - mainMetrics *codegen.MethodMetrics + stub codegen.Stub } // Check that main_client_stub implements the weaver.Main interface. var _ weaver.Main = (*main_client_stub)(nil) -func (s main_client_stub) Main(ctx context.Context) (err error) { - // Update metrics. - start := time.Now() - s.mainMetrics.Count.Add(1) - - span := trace.SpanFromContext(ctx) - if span.SpanContext().IsValid() { - // Create a child span for this method. - ctx, span = s.stub.Tracer().Start(ctx, "main.Main.Main", trace.WithSpanKind(trace.SpanKindClient)) - } - - defer func() { - // Catch and return any panics detected during encoding/decoding/rpc. - if err == nil { - err = codegen.CatchPanics(recover()) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - } - } - - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - s.mainMetrics.ErrorCount.Add(1) - } - span.End() - - s.mainMetrics.Latency.Put(float64(time.Since(start).Microseconds())) - }() - - var shardKey uint64 - - // Call the remote method. - s.mainMetrics.BytesRequest.Put(0) - var results []byte - results, err = s.stub.Run(ctx, 0, nil, shardKey) - if err != nil { - err = errors.Join(weaver.RemoteCallError, err) - return - } - s.mainMetrics.BytesReply.Put(float64(len(results))) - - // Decode the results. - dec := codegen.NewDecoder(results) - err = dec.Error() - return -} - // Server stub implementations. type main_server_stub struct { @@ -137,28 +66,7 @@ var _ codegen.Server = (*main_server_stub)(nil) // GetStubFn implements the codegen.Server interface. func (s main_server_stub) GetStubFn(method string) func(ctx context.Context, args []byte) ([]byte, error) { switch method { - case "Main": - return s.main default: return nil } } - -func (s main_server_stub) main(ctx context.Context, args []byte) (res []byte, err error) { - // Catch and return any panics detected during encoding/decoding/rpc. - defer func() { - if err == nil { - err = codegen.CatchPanics(recover()) - } - }() - - // TODO(rgrandl): The deferred function above will recover from panics in the - // user code: fix this. - // Call the local method. - appErr := s.impl.Main(ctx) - - // Encode the results. - enc := codegen.NewEncoder() - enc.Error(appErr) - return enc.Data(), nil -} diff --git a/weavelet.go b/weavelet.go index 1b56b426a..2111f0ae6 100644 --- a/weavelet.go +++ b/weavelet.go @@ -260,21 +260,6 @@ func (w *weavelet) getMainIfLocal() (*componentImpl, error) { return nil, nil } -func (w *weavelet) Wait(ctx context.Context) error { - // Call weaver.Main.Main if weaver.Main is hosted locally. - impl, err := w.getMainIfLocal() - if err != nil { - return nil - } - if impl != nil { - return impl.impl.(Main).Main(ctx) - } - - // Run until cancelled. - <-ctx.Done() - return ctx.Err() -} - func (w *weavelet) Get(requester string, compType reflect.Type) (any, error) { component, err := w.getComponentByType(compType) if err != nil { diff --git a/weaver.go b/weaver.go index 9ea4ec4c3..60522e6d1 100644 --- a/weaver.go +++ b/weaver.go @@ -32,6 +32,7 @@ import ( "sync" "github.com/ServiceWeaver/weaver/internal/private" + "github.com/ServiceWeaver/weaver/internal/reflection" "github.com/ServiceWeaver/weaver/runtime/codegen" ) @@ -92,40 +93,60 @@ const ( var healthzInit sync.Once +// PointerToMain is a type constraint that asserts *T is an instance of Main +// (i.e. T is a struct that embeds weaver.Implements[weaver.Main]). +type PointerToMain[T any] interface { + *T + InstanceOf[Main] +} + // Run runs app as a Service Weaver application. // // The application is composed of a set of components that include // weaver.Main as well as any components transitively needed by -// weaver.Main. An instance that implement weaver.Main is -// automatically created by weaver.Run and its Main method called. -// Note: other replicas in which weaver.Run is called may also create -// instances of weaver.Main. +// weaver.Main. An instance that implement weaver.Main is automatically created +// by weaver.Run and passed to app. Note: other replicas in which weaver.Run +// is called may also create instances of weaver.Main. +// +// The type T must be a struct type that contains an embedded +// `weaver.Implements[weaver.Main]` field. A value of type T is +// created, initialized (by calling its Init method if any), and a +// pointer to the value is passed to app. app contains the main body of +// the application; it will typically run HTTP servers, etc. // // If this process is hosting the `weaver.Main` component, Run will -// call its Main method and will return when that method returns. If -// this process is not hosting `weaver.Main`, it will never +// call app and will return when app returns. If this process is +// hosting other components, Run will start those components and never // return. Most callers of Run will not do anything (other than // possibly logging any returned error) after Run returns. // // func main() { -// if err := weaver.Run(context.Background()); err != nil { +// if err := weaver.Run(context.Background(), app); err != nil { // log.Fatal(err) // } // } -func Run(ctx context.Context) error { +func Run[T any, _ PointerToMain[T]](ctx context.Context, app func(context.Context, *T) error) error { // Register HealthzHandler in the default ServerMux. healthzInit.Do(func() { http.HandleFunc(HealthzURL, HealthzHandler) }) - app, err := internalStart(ctx, private.AppOptions{}) + wlet, err := internalStart(ctx, private.AppOptions{}) if err != nil { return err } - return app.Wait(ctx) + if wlet.info.RunMain { + main, err := wlet.GetImpl("weaver.Run", reflection.Type[T]()) + if err != nil { + return err + } + return app(ctx, main.(*T)) + } + <-ctx.Done() + return ctx.Err() } -func internalStart(ctx context.Context, opts private.AppOptions) (private.App, error) { +func internalStart(ctx context.Context, opts private.AppOptions) (*weavelet, error) { w, err := newWeavelet(ctx, opts, codegen.Registered()) if err != nil { return nil, fmt.Errorf("error initializating application: %w", err) @@ -138,5 +159,7 @@ func internalStart(ctx context.Context, opts private.AppOptions) (private.App, e func init() { // Provide weavertest with access to weavelet. - private.Start = internalStart + private.Start = func(ctx context.Context, opts private.AppOptions) (private.App, error) { + return internalStart(ctx, opts) + } } diff --git a/website/docs.md b/website/docs.md index 08ca09693..a021817f5 100644 --- a/website/docs.md +++ b/website/docs.md @@ -117,27 +117,27 @@ import ( ) func main() { - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } // app is the main component of the application. weaver.Run creates -// it and calls its Main method. +// it and passes it to serve. type app struct{ weaver.Implements[weaver.Main] } -// Main is called by weaver.Run and contains the body of the application. -func (*app) Main(context.Context) error { +// serve is called by weaver.Run and contains the body of the application. +func serve(context.Context, *app) error { fmt.Println("Hello") return nil } ``` -`weaver.Run` initializes and runs the Service Weaver application. In -particular, `weaver.Run` finds the main component, creates it, and calls its -Main method. In this example,`app` is the main component since it +`weaver.Run(...)` initializes and runs the Service Weaver application. In +particular, `weaver.Run` finds the main component, creates it, and passes it to +a supplied function. In this example,`app` is the main component since it contains a `weaver.Implements[weaver.Main]` field. Before we build and run the app, we need to run Service Weaver's code generator, @@ -221,7 +221,7 @@ import ( ) func main() { - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } @@ -231,7 +231,7 @@ type app struct{ reverser weaver.Ref[Reverser] } -func (app *app) Main(ctx context.Context) error { +func serve(ctx context.Context, app *app) error { // Call the Reverse method. var r Reverser = app.reverser.Get() reversed, err := r.Reverse(ctx, "!dlroW ,olleH") @@ -277,7 +277,7 @@ import ( ) func main() { - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } @@ -288,7 +288,7 @@ type app struct { hello weaver.Listener } -func (app *app) Main(ctx context.Context) error { +func serve(ctx context.Context, app *app) error { // The hello listener will listen on a random port chosen by the operating // system. This behavior can be changed in the config file. fmt.Printf("hello listener available on %v\n", app.hello) @@ -1090,7 +1090,7 @@ import ( ) func main() { - if err := weaver.Run(context.Background()); err != nil { + if err := weaver.Run(context.Background(), serve); err != nil { log.Fatal(err) } } @@ -1100,7 +1100,7 @@ type app struct { lis weaver.Listener } -func (app *app) Main(ctx context.Context) error { +func serve(ctx context.Context, app *app) error { fmt.Printf("hello listener available on %v\n", app.lis) // Serve the /hello endpoint.