Netflix / Prana

A sidecar for your NetflixOSS based services.
Apache License 2.0
502 stars 98 forks source link

Load Groovy based request handlers during startup of Prana from filesystem #4

Open diptanu opened 9 years ago

diptanu commented 9 years ago

Prana serves the purpose of exposing features of the various client libraries like Eureka, Servo, Ribbon etc. Users should be able to expose APIs of those libraries in a manner that's suitable to their application in case we don't or our default APIs don't serve their use case.

Users of Prana could pass a command line argument --filters-location=/path/to/filters. Prana would scan the location for Groovy classes which implements the PranaHttpExtension interface and compile them and wire them up with the http router. Extensions would be only loaded during the application startup.

The Prana interface looks like -

public interface PranaHttpExtension extends RequestHandler<ByteBuf, ByteBuf> {
    public String getRoute();
}

and a sample extension implementation would look like this

public class ExampleHttpHandler implements PranaHttpExtension {

    private DiscoveryClient discoveryClient;

    private ObjectMapper objectMapper;

    @Inject
    public ExampleHttpHandler(DiscoveryClient discoveryClient, ObjectMapper objectMapper) {
        this.discoveryClient = discoveryClient;
        this.objectMapper = objectMapper;
    }

    @Override
    public String getRoute() {
        return "/getregions";
    }

    @Override
    public Observable<Void> handle(HttpServerRequest<ByteBuf> request, HttpServerResponse<ByteBuf> response) {
        response.getHeaders().add("Content-Type", "application/json");
        try {
            byte[] bytes = objectMapper.writeValueAsBytes(discoveryClient.getAllKnownRegions());
            response.writeBytes(bytes);
            response.setStatus(HttpResponseStatus.OK);
        } catch (JsonProcessingException e) {
            response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
        }
        return response.close();
    }
}

Prana extensions would be able to inject objects that are instantiated by Guice.

cfieber commented 9 years ago

Is the intention to load them in some sort of sandbox? Seems like there could be a known location that was added to the classpath by the prana start script ($PRANA_HOME/ext or something) That also eliminates the groovy compile step and opens things up to additional jvm languages.

In terms of discovering extensions what is the proposed strategy there? Looking for a META-INF/prana/extensions.properties file that lists implementation classes (similar to gradle plugin model) could work (as opposed to regex'ing groovy files or something)

It would be worthwhile for extension developers to have a prana-extension-api library that exports the set of things an extension can inject as well as the definition of the PranaHttpExtension class

diptanu commented 9 years ago

@cfieber With regards to sandboxing extensions, we are not going to do classloader isolation for extensions. The current model of adding the $PRANA_HOME/ext to the Prana classpath has some drawbacks. For example an user could have a different version of Guice than what Prana itself needs, and in that case the application might crash unless we do proper classloader isolation for extensions.

So far the only use case for extensions has been to expose features of the client libraries of various components via rest endpoints. I would like to defer building a proper classloader isolated extension model until the need arises.

In terms of discovering extensions we could use JDK's Service Loader which is supported by Governator.

diptanu commented 9 years ago

@cfieber I like the idea of the prana-extension-api which provides the injectable set of things. Do you have any examples?

aspyker commented 8 years ago

@diptanu Thank you for the contribution. More will be coming, but please see http://ispyker.blogspot.com/2015/10/towards-being-better-about-open-source.html for a bit of context on the status of this project.