Nike-Inc / riposte

Riposte is a Netty-based microservice framework for rapid development of production-ready HTTP APIs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Questions / forums / mailing list?

alesj opened this issue · comments

What's the best / easiest way to ask any questions or start a debate about Riposite and its components?
By opening similar issue? :-)

e.g. what's the best way to integrate/use Fastbreak, Backstopper, Wingtips?
Imho, some AOP-like (+ annotations on methods / classes) approach would fit best if there is a lot of code to intercept / integrate.
Does something like that already exist; e.g. a Guice interceptors?

@alesj sorry for the delay!

I see three main parts to your question. I'll let @tlockney do some investigation on the first part around best ways to ask questions or discuss features/components. Until we get something setup that's geared towards those concerns the best bet is probably raise an issue - happy to answer questions and discuss things. For the other two parts I'll put them in followup comments.

@alesj Second part of your question, regarding the best way to integrate/use fastbreak, backstopper, and/or wingtips: if your question is about using them in general (i.e. not in a Riposte project) then that's no problem - they are fully independent and usable anywhere. Please read the readmes on the individual projects and see if you can figure out how to use them. If not then that indicates a gap in documentation and we'd love to get some issues raised so we can fix any documentation or usability issues.

If the question on fastbreak/backstopper/wingtips is about using them in riposte, the quick answer is they are already integrated to a large degree and you don't need to do anything special. The longer answer is:

  • Wingtips: All incoming calls to Riposte are automatically surrounded with a wingtips distributed tracing span. If the incoming call contains the X-B3-* propagation headers then the riposte request will be surrounded with a child span of the incoming call's span. If the incoming call does not contain trace propagation headers then a new trace will be started. For downstream calls made in the middle of a riposte request you will need to add the B3 headers yourself as described in the wingtips readme here, unless you're using the riposte AsyncHttpClientHelper, in which case the distributed trace stuff will be propagated for you automatically.
  • Backstopper: Backstopper is the default error handling system for riposte. See the javadocs for ServerConfig.riposteErrorHandler() and ServerConfig.riposteUnhandledErrorHandler() for info on how to provide your project's errors so that they are available to backstopper when interpreting exceptions. For general backstopper usage see the backstopper readme. For more info on backstopper in riposte see the example endpoint in the microservice template (also note the error handling section of the template project's readme).
  • Fastbreak: Fastbreak is built into the proxy/router endpoints and AsyncHttpClientHelper and is optional for both those cases. Beyond that you can use fastbreak independently in any place you want - see the fastbreak readme for usage details.

@alesj Last part of your question, about AOP/annotation style approach to integration. This is a tricky one because it's largely personal preference. Part of the philosophy in wingtips, backstopper, fastbreak, and riposte is that there should be no magic in the core - no AOP, no custom annotations, no classpath scanning, no bytecode manipulation, etc. Here are some personal opinions on why this is the way it is:

  1. Magic like that is great... until something goes wrong (and it always goes wrong eventually either due to a bug in the library or the user not understanding how to use it properly), at which point it can be exceedingly difficult and time consuming to debug, both for library developers and end users. I like being able to put a breakpoint somewhere and follow the code to see exactly what's happening.
  2. End users are usually forced to refer to huge volumes of outside user-guide style documentation for everything magic-related because it's not obvious in the code what your options are, or where the code that actually does the work lives. I much prefer the ability to look at what methods are available and have accurate, complete javadocs so that everything I need is at my fingertips in the IDE while I'm developing.
  3. The above issues leads to an excess of "development-via-stackoverflow" where instead of understanding the libraries you're using you resort to google searches, tutorials, stackoverflow, etc, to try and find someone who did something similar to what you want to do.
  4. By having no magic in the core functionality we also maximize compatibility and flexibility. No need for any special IDE plugins (which are often buggy and/or slow down your IDE and/or lag behind when the IDE is updated) to understand what's happening. Plus it lets anybody add their own personal favorite magic themselves - no restrictions on development environment or plugins. You can add your own annotation processing, or AOP, or use lombok, or scala, or anything else with these libraries and know that they will work without jumping through a bunch of painful hoops to get it running and worrying about fragility, conflicts, or dependency hell as lib versions are updated.

Following on that last point, this doesn't mean magic is outlawed entirely for wingtips/backstopper/fastbreak/riposte. It just means that the core functionality is magic-free. The magic can be added in appropriate plugin modules, for example here is a Guice module for easily wiring up backstopper to riposte with your project's errors.

For another example we have an internal plugin module that lets you use JAX-RS/Jersey annotations to define endpoints in a Riposte project. It's experimental and not really being used heavily so it may or may not be open sourced in the future, but it does work and it shows that the no-magic-in-the-core philosophy allows for those cool plugin modules to exist without clashing or breaking or preventing other modules (i.e. we could theoretically have the JAX-RS/Jersey plugin and a Spring MVC plugin, and users could choose which one they wanted without being forced into anything).

(Very) long story short, if you have ideas for annotation, AOP, bytecode manipulation, etc type features you won't be shut down, but the functionality will need to be added via separate modules. If you can't build that functionality without hooks in the core that don't currently exist then that's ok too - we can usually find a way to add the necessary hooks to the core classes.

Hope all that makes sense?

@alesj @nicmunroe For now, Github issues are the best way to handle discussion around features, best practices, etc. We'll continue to explore other (possibly better?) options over time.

Hope all that makes sense?

Yeah, perfect.
Very useful (long) explanation. :-)

Wrt my ideas, I'll try to find some time to play more with Riposite, and then see if I'm missing anything.
It would be great if I can contribute something back.

@alesj Awesome, we'd love to have you contribute! If you want to bounce ideas/design off us feel free to open an issue regarding the stuff you want to work on and we can go over it before you do a bunch of coding work. Or if you prefer to code it up first and discuss over a PR that's fine too.

Closing this issue as I think we've covered your questions?