Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO-NOT-MERGE] spike - gRPC support #571

Closed
wants to merge 3 commits into from
Closed

[DO-NOT-MERGE] spike - gRPC support #571

wants to merge 3 commits into from

Conversation

bajtos
Copy link
Member

@bajtos bajtos commented Sep 13, 2017

Add an initial version of gRPC support, using API/protocol-first approach.

Connect to #521

@bajtos bajtos added the spike label Sep 13, 2017
@bajtos bajtos self-assigned this Sep 13, 2017
@bajtos bajtos changed the title feat: spike - gRPC support [DO-NOT-MERGE] spike - gRPC support Sep 13, 2017
Add an initial version of gRPC support, using API/protocol-first
approach.
// tslint:disable-next-line:no-any
const greeter: any = {};

Object.keys(client.__proto__).forEach(method => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Object. getPrototypeOf(client) instead?

// TODO(bajtos) serviceSpec needs to be typed
export function service(serviceSpec: any) {
return function(controllerCtor: Function) {
(controllerCtor as any).grpcService = serviceSpec;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a good practice to mutate the class directly instead of Reflector?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see two issues with Reflector:

  • It relies on having a single reflect-metadata package in node_modules tree, which cannot be reliably achieved.
  • It's difficult to use from JavaScript codebase.

Creating a static property on the constructor class solves both issues and it's the same approach we are already using for Model.definition in our repository package. I think we should eventually use this approach for storing OpenAPI spec too.

Thoughts?

cc @kjdelisle @virkt25

Copy link
Contributor

@kjdelisle kjdelisle Sep 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, for the first reason alone; if others are making use of reflect-metadata, which is entirely likely, it could impact us.

methodName: string,
rootContext: Context,
) {
// TODO(bajtos) support metadata?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request.metadata contains gRPC metadata from the client call, like http headers.

debug('gRPC invoke %s.%s(%j)', controllerName, methodName, request);

// FIXME(bajtos) Create new per-request child context
// FIXME(bajtos) Use Sequence to allow custom request processing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

return function(request: any, callback: any) {
debug('gRPC invoke %s.%s(%j)', controllerName, methodName, request);

// FIXME(bajtos) Create new per-request child context
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. The request.metadata can be bound to the child context.

}

it('provides gRPC interface for decorated controllers', async () => {
@service(helloService.Greeter.service)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also consider to reference the gRPC spec file or json representation.

it('provides gRPC interface for decorated controllers', async () => {
@service(helloService.Greeter.service)
class MyController implements Greeter {
hello({name}: HelloRequest): HelloResponse {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A method-level gRPC decorator is useful too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method level dependency injection will be interesting too, for example:

hello(@inject('grpc.request#name') name: string, 
      @inject('grpc.request#metadata.clientid') clientId: string): HelloResponse {
...
}


// TODO(bajtos) serviceSpec needs to be typed
export function service(serviceSpec: any) {
return function(controllerCtor: Function) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it important that we append the property to the target as-is, or can we extend it with the decorator?

export function service(serviceSpec: any) {
  return function newClass<T extends {new(...args: any[]):{}}>(target: T) {
      return class extends target {
        grpcService: any = serviceSpec;
      }   
  }
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think it should be ok to return a new class in the decorator. But then what are the downsides of appending the static property the existing controller class? Is the extra complexity worth it?

One of my concerns is that controllers decorated with @services will have anonymous class name or the same class name newClass for all controllers. This will make (error) stack traces rather unhelpful, as we are already experiencing with juggler models that all have the sam class name ModelConstructor (see lib/model-builder.js).

@bajtos
Copy link
Member Author

bajtos commented Sep 15, 2017

The last commit is adding very basic support for gRPC Sequence. I'll post a longer comment to #521

The tests are crashing with Segmentation Fault, I was not able to track down the exact source of the problem yet. Another reason why to be careful about the grpc module?

@bajtos
Copy link
Member Author

bajtos commented Sep 19, 2017

Closing without merging, the purpose of this PR was to verify that gRPC can be implemented.

@bajtos bajtos closed this Sep 19, 2017
@bajtos bajtos deleted the spike/grpc branch September 19, 2017 14:17
@bajtos bajtos removed the review label Sep 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants