Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Distributed, Asynchronous RESTful Framework Prototype

DZone's Guide to

A Distributed, Asynchronous RESTful Framework Prototype

Concepts of asynchronous RESTful operations were already doing the rounds (see here), even before JAX-RS 2.0 introduced the server-side asynchronous processing API. Taking a cue from the concepts, we propose a prototype architecture for an asynchronous and distributed JAX-RS provider.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90-day trial of 3Scale by Red Hat

Concepts of asynchronous RESTful operations were already doing the rounds (see here), even before JAX-RS 2.0 introduced the server-side asynchronous processing API. The very basic principle behind asynchronous RESTful API is pretty simple. We have a DZone article describing how Jersey has implemented JAX-RS 2.0, and some information on the specifications.

Taking a cue from the concepts, we propose a prototype architecture for an asynchronous and distributed JAX-RS provider:

  1. Instead of dispatching the request to a JAX-RS annotated service method, suspend the operation somehow. Then, instead of returning a 201 or 200 HTTP response, issue a 202 (Accepted) response.

  2. Set a redirection URL with a 'Location' header in response.

  3. The suspended operation should be handled by a delegate in an asynchronous manner. Once complete, the response resource should be created at the above-mentioned URL.

  4. The client would then need to do a HTTP GET on the redirection URL to get the actual response. The GET would either return the response resource or, either a 204 or 404, depending on the request processing state.

Invocation Delegation

Suspension of the invocation would imply dispatching the processing asynchronously to some other component of the provider. From JAX-RS perspective, this processing component would need to invoke an (annotated) method on a plain Java class via introspection, and probably pass the query/path params and/or POST content as arguments to it. 

If we build the provider on top of a data distribution platform (data grid), then we can distribute the request data (arguments, request details, correlationid). A receiving member would then need to dispatch the request data to the processor component, which would actually execute the invocation. The response would be stored in the data grid, corresponding to the correlationid.

This correlationid would have been sent back to the client, as a part of the redirection URL.

Hazelcast

We used Hazelcast as the data grid provider in this project. The distributed IMap, provided by Hazelcast can have local entry listeners attached to it. Entry listeners receive callbacks on map entry events like put/get/remove etc. Thus, whenever a request data is added (put) to a distributed map, an entry listener on the data owning node will be notified. The received data would be delegated to the processing component, to perform the dispatch to JAX-RS annotated service methods.

I have tried to represent it pictorially using a sequence diagram. Well, this may not be the best example of an SD usage, but it will probably bring out the basic idea.

Flow

Design

The following logical components would be required in order to design the platform:

  • An HTTP server component that would be able to map a RESTful URI to a method invocation (REST Listener)

    • Intercept HTTP requests and parse request parameters/body

    • Prepare serializable request data structure

    • Generate HTTP response

  • A discovery component to auto-discover and register JAX-RS annotated elements (RequestDispatcher)

    • Auto-discover JAX-RS annotated elements and prepare method invocation metadata

    • Map the method invocation metadata to uri pattern

    • Execute method invocation

  • A Hazelcast component capable of registering local entry listeners and perform distributed map operations (HazelcastService)

    • Register local entry listener callback that gets notified on distributed map entry event

    • Provide a facade for map operations on Hazelcast data grid

Using this approach for asynchronous RESTful processing, we can delegate execution not only in separate worker threads, but as well as on separate worker nodes. As an afterthought, the framework can well be extended to implement a distributed microservice provider.

Code Samples

A Spring Boot project is available on GitHub. The REST Listener is built on top of a lightweight, open-source Netty-based library, Webbit.

Being a prototype project, it has some limitations as of now. Basically the project implements a small subset of the JAX RS 2.0 specs.

  1. Only JSON request/response is consumed/produced.

  2. Only GET/POST/DELETE is supported.

  3. For the asynchronous server API AsyncResponse, not all operations are supported. Details documented in code.

Given below is an example of an async REST service. The interesting point to note here is that the actual method invocation is guaranteed to be executed on a separate thread (and probably in a separate JVM altogether) asynchronously. 

On invocation of asyncResponse.resume(), the response is made available at resource URI, as shared in the initial response.

@GET
  @Path("/async")
//the first argument has to be @Suspended AsyncResponse type
//an optional second argument, if present, is the deserialized JSON
//content of the request (for POST)
  public void helloAsync(@Suspended AsyncResponse asynResponse)
  {
    //No separate asynchronous strategy is required here.
    //This method will automatically be executed in a separate worker (thread/node)

    Object returned = invokeMySuperHeavyService();
    asynResponse.resume(returned);

    //Now the response is committed and made available as JSON

  }


Explore the core elements of owning an API strategy and best practices for effective API programs. Download the API Owner's Manual, brought to you by 3Scale by Red Hat

Topics:
asynchronous ,rest api ,hazelcast ,java

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}