Easily Circuit Breaking gRPC Node calls with Hystrixjs in a graphQL server

Hey! This is the third post on a series talking about nodejs, gRPC, rxjs, graphQL and now circuit breaking with hystrixjs:

  1. Making a node gRPC client reactive with rxjs
  2. Integrating reactive gRPC in Node with GraphQL
  3. Circuit Breaking the gRPC calls (this post)
  4. Testing the gRPC calls mocking the responses and streams

Before going further, if you are not sure what Circuit Breaking means I would suggest reading the pattern from here.

Note: The circuit breaking technique that I will show can be done in other contexts than just graphQL, so my example should work on any other context where a call might need circuit breaking.

Hystrixjs

I’ll let the hystrix repo explain what it is in case you don’t know:

[Hystrixjs] is inspired by the by the the Netflix Hystrix module for Java applications, which “is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable”.

We will use Hystrixjs as it’s the most complete and simplest approach I found, and that’s something I like to find.

As simple as Circuit Breaking can get

// CommandsBuilder.js

import { commandFactory } from "hystrixjs";

export const CommandsBuilder = class CommandsBuilder {

	static createMyCommand({runFn, fallbackFn}){
		let fallback = fallbackFn || () => console.log("up to you!");
		
		return commandFactory.getOrCreate("my-external-service-command")
			// function that calls the external service, needs to return a Promise
			.run(runFn)
			// function called if the service is down or slow
			.fallbackTo(fallback)
			.build();
	}

};
  • runFn: The function that calls the external service, needs to return a Promise
  • fallbackFn: The function called if the service is down or slow

More configuration options under Creating a command in Hystrixjs readme and the general flow of a command is also shown there.

Alt text

Bringing gRPC in

We make the gRPC call through the client but wrapping it in our Hystrixjs runFn command:

import {CommandsBuilder} from './CommandsBuilder';
import RxGrpcUtils from './RxGrpcUtils'; // see Post 1

const grpcCommand = CommandsBuilder.createGetSomethingCommand({
				runFn: () => {
					return RxGrpcUtils.grpcToObservable(
						// I need the binding because of a change in context I was 
						// facing while running the call, check if it's necessary in your case
						grpcClient.getSomething.bind(grpcClient),
						{
							/* some data to pass to the grpc call? */
						}
					)
				});
grpcCommand.execute().then(() => console.log("gRPC call done!"));	

Bringing graphQL resolvers in

// graphql-resolvers.js

import grpcClient from './grpcClient'; // see Post 1
import RxGrpcUtils from './RxGrpcUtils';  // see Post 1

export default {
	Query: {
		getSomething: (obj, args, context, info) => {
			return CommandsBuilder.createGetSomethingCommand({
				runFn: () => {
					return RxGrpcUtils.grpcToObservable(
						grpcClient.getSomething.bind(grpcClient),
						{
							/* some data to pass to the grpc call? */
						}
					).toPromise(); // the runFn needs to return a Promise
				}
			}).execute(); // returns a Promise, as gql wants
		}
	Mutation: { /* ... */ }
};

Putting it all together

  1. The gRPC call is made reactive (see Making a node gRPC client reactive with rxjs)
  2. Later (in this method) is made a Promise to be consumed by the CommandBuilder we created using Hystrixjs
  3. The execution of the Hystrixjs command returns a Promise, which is exactly what graphQL wants in the resolver
  4. Hystrixjs will run the gRPC call, if the command configuration determines that the call has to be circuit broken, it will call the fallback function, if not, the call will continue to graphQL

Note: Promise rejection can be handled at the rxjs level or command execution level before it gets to graphQL. This wrappers give you enough flexibility to handle rejections as you see fit.

Hope it helps and let me know if you found it useful and/or if you’d like to read more about this.

Cheers!

Blog Logo

Tomas Alabes

Software Engineer, author, blogger and obsessive learner, from Argentina living in Silicon Valley


Published

Image

Tomas Alabes' Blog

My personal site's blog

Back to Overview