Releases: advantageous/qbit
QBit Java Reactive Microservices Lib Release 0.9.7
QBit Java Reactive Microservices Lib.
Updated to match Reakt 1.0.0.RELEASE.
You can now use Reakt Reactor instead of QBit Reactor on new projects.
QBit Java Reactive Microservices Lib Release 0.9.5
This is mostly to fix an issue with the maven pom that was introduced in the QBit Release 0.9.4.
There is also some code formatting.
QBit Java Reactive Microservices Lib Release 0.9.4
QBit Java Reactive Microservices Lib Release 0.9.4.
Added support for Reakt and started using it.
Also changed QBit Callbacks to be more compatible with Reakt Callbacks to make the transition easier.
QBit Java Reactive Microservices Lib Release 0.9.3
- 660 Report back HttpClient connection issues
- Implemented new Vertx EventBus bridge so QBit Microservice lib services can be called over the event bus.
- 659 Improved WebSocket connection open handling of QBit microservices exposed over websocket
- 656 Added Reactor One Shot task
/* Add a task that repeats every ten seconds. */
reactor.addOneShotAfterTask(10, TimeUnit.SECONDS, () -> {
test.set(true);
count.incrementAndGet();
});
- 635 Improved Dispatch so creating things like Vertx EventBus bridge to QBit Microservices Lib possible
- 631 Improved Serialization JSON strictness
- 620 Added ability to filter requests before body is read to do things like filter on HttpRequest body size
- 618 Fixed Hibernate Annotation breaking QBit problem
- 614 Filters for HttpRequest and HttpResponse was added to support things like CORS response filters
- 610 WebSocket RPC call fixes
- Implemented Reactive Streams support
- 591 Fixed form handling issue when running embedded in Vertx instead of using Vertx as lib
- 589 JSON list serialization was not working with nulls in list properly
- 587 implement form params as part of http request
- 586 issue warning if there is an attempt to create an interface with a blocking cal
- 583 ServiceQueue should empty queue on stop
- 582 EventManager.joinService needs a corresponding EventManager.leaveService
- 576 addResponseDecorator is creating duplicate http headers
- 575 of NoCache Header entry increments in every request if @NoCacheHeader is uses.
- 574 missing uri params was throwing an index out of bounds exception
- 571 improved health system so it is fit to track errors and report them to monitoring systems
- Added MDC support so that REST/WebSocket services can pass Logging MDC support to other downstream services. Request headers, request id, request info, etc. can be tracked in log to track down log message to originating request. See MDC support documents. There were several Github issues/tasks with this effort. MDC is essential for reactive Java Microservices.
final ManagedServiceBuilder managedServiceBuilder = managedServiceBuilder().setRootURI("/");
managedServiceBuilder.enableLoggingMappedDiagnosticContext();
- 568 Custom response when a message can't be parsed
- Fixed integration issues with Guice interceptors and QBit Microservices Lib.
- 563 Improved runtime speed of vertx tests
- 562 Improve speed of websocket method call handling
- 560 We were unable to send binary messages in websocket only text. Now we can send either text or binary
- 559 Unable to open WebSocket connection message was confusing. Improved WebSocket handling and error messages
- 549 Change QBit to ignore private methods and @IgnoreMethod
- We added DNS SVR records to the service discovery lib. 545 Improve DNS support
- 540 Added Header annotation for all endpoints so we can properly control HTTP cache headers
- 539 @RequestParam, @PathVariable, @HeaderParam does not give null value for optional request param.
- 534 Made EventBusQueueAdapter recoverable by using a supplier
- 533 Added base service class that takes a reactor, timer and statsCollector
- 529 Map<String, Object> does not allow deeply nested lists and maps for JSON serialization / deserialization
- 528 Take out hostname as an option for StatsReplication (some stats system encode the host name, some don't)
- 526 Document a service marking itself in a failed state
- 523 Add debugging for non started queues and queues that are filling up
- 521 If batching is set to 1, create a no batch queue
- We refactored the core Queuing classes, speed them up and simplified them.
- Added JMS as a QBit queue support
- 520 Support @GET, @DELETE, @HEAD, @POST, @PUT annotation in addition to @RequestMapping
- 518 We now support Swagger for TextHttpResponse
- 517 Add ability to specify a different contentType via RequestMapping
- 516 QBit needs to ignores Scala generated methods
- We added support to work with Scala from QBit.
- 513 AsyncFutureBuilder for legacy integration and unit testing. Add support to make a blocking call to a non-blocking interface via a blocking get operation
- AsyncFutureBuilder can support blocking calls for legacy integration and unit testing
- 499 Create websocket service client (ClientFactory) that is ServiceDiscovery aware
QBit 0.9.1 Release
There were a lot of features added that users asked for (some a long time ago).
As we touch things to add JSend, we found easy ways to add some features users have been asking for.
There is also some docs for JMS support, Kafka support, DNS Service Discovery, sending back HTTP response codes other than 200, and 202, sending error response codes other than 500, service discovery aware web socket proxies, kv store/ kv cache support for Redis (async), improvements in speed for services with just a few clients (QBit was built for high-volume so we had to add some things to make it faster for low volume), and more.
1) Support for non-JSON bodies from REST end-points
Added support for String and byte[] to be passed without JSON parsing.
Issue.
Docs Added to wiki main.
@RequestMapping(value = "/body/bytes", method = RequestMethod.POST)
public boolean bodyPostBytes( byte[] body) {
String string = new String(body, StandardCharsets.UTF_8);
return string.equals("foo");
}
@RequestMapping(value = "/body/string", method = RequestMethod.POST)
public boolean bodyPostString(String body) {
return body.equals("foo");
}
If the Content-Type of the request is null
or is application/json
then we will parse the body as JSON.
If the Content-Type is set and is not application/json
then we will pass the raw String or raw bytes. This allows you to handle non-JSON content from REST. It does not do any auto-conversion. You will get the raw bytes or raw UTF-8 string.
@Test
public void testNoJSONParseWithBytes() {
final HttpTextResponse httpResponse = httpServerSimulator.sendRequest(
httpRequestBuilder.setUri("/es/body/bytes")
.setMethodPost().setContentType("foo")
.setBody("foo")
.build()
);
assertEquals(200, httpResponse.code());
assertEquals("true", httpResponse.body());
}
@Test
public void testNoJSONParseWithString() {
final HttpTextResponse httpResponse = httpServerSimulator.sendRequest(
httpRequestBuilder.setUri("/es/body/string")
.setMethodPost().setContentType("foo")
.setBody("foo")
.build()
);
assertEquals(200, httpResponse.code());
assertEquals("true", httpResponse.body());
}
2) Added HttpProxy support
You can proxy backend services from a single endpoint.
This also allows you to do actions before sending the request, and to not forward the request based on a Predicate.
3) Added ability to return different response codes for success
By default QBit sends a 200 (OK) for a non-void call (a call that has a return or a Callback
).
If the REST operation has no return or no callback then QBit sends a 202 (Accepted).
There may be times when you want to send a 201 (Created) or some other code that is not an Exception.
You can do that by setting code
on @RequestMapping
. By default the code is -1 which means use the default behavior.
Issue
Docs Added to wiki main.
@RequestMapping(value = "/helloj7", code = 221)
public void helloJSend7(Callback<JSendResponse<List<String>>> callback) {
callback.returnThis(JSendResponseBuilder.jSendResponseBuilder(Lists.list(
"hello " + System.currentTimeMillis())).build());
}
4) Working with non JSON responses
Issue
Docs Added to wiki main.
You do not have to return JSON form rest calls.
You can return any binary or any text.
4.1) Returning non JSON from REST call
@RequestMapping(method = RequestMethod.GET)
public void ping2(Callback<HttpTextResponse> callback) {
callback.returnThis(HttpResponseBuilder.httpResponseBuilder()
.setBody("hello mom").setContentType("mom")
.setCode(777)
.buildTextResponse());
}
4.2) Returning binary from REST call
@RequestMapping(method = RequestMethod.GET)
public void ping2(Callback<HttpBinaryResponse> callback) {
callback.returnThis(HttpResponseBuilder.httpResponseBuilder()
.setBody("hello mom").setContentType("mom")
.setCode(777)
.buildBinaryResponse());
}
5) Create websocket service client that is ServiceDiscovery aware
ServiceDiscovery-aware websocket service client
final Client client = clientBuilder
.setServiceDiscovery(serviceDiscovery, "echo")
.setUri("/echo").setProtocolBatchSize(20).build()
.startClient();
final EchoAsync echoClient = client.createProxy(EchoAsync.class, "echo");
Currently the clientBuilder
will load all service endpoints that are registered under the service name,
and randomly pick one.
In the future we can RoundRobin calls or shard calls to websocket service and/or provide auto fail over if the connection is closed. We do this for the event bus that uses service discovery but it is not baked into WebSocket based client stubs yet.
For comparison here is a non-ServiceDiscovery version.
final ClientBuilder clientBuilder = ClientBuilder.clientBuilder();
final Client client = clientBuilder.setHost("localhost")
.setPort(8080).setUri("/echo")
.build().startClient();
final EchoAsync echoClient = client.createProxy(EchoAsync.class, "echo");
Recall ServiceDiscovery
includes Consul based, watching JSON files on disk, and DNS SVR records. It is easy to write your own service discovery as well and plug it into QBit.
6) JSend support for serialization and swagger
We started to add JSend support.
The JSend is supported for marshaling JSend objects, and via our Swagger support.
@RequestMapping("/hw")
public class HelloWorldJSend {
public static class Hello {
final String hello;
public Hello(String hello) {
this.hello = hello;
}
}
@RequestMapping("/hello")
public String hello() {
return "hello " + System.currentTimeMillis();
}
@RequestMapping("/helloj")
public JSendResponse<String> helloJSend() {
return JSendResponseBuilder.jSendResponseBuilder("hello " + System.currentTimeMillis()).build();
}
@RequestMapping("/helloj2")
public JSendResponse<Hello> helloJSend2() {
return JSendResponseBuilder.jSendResponseBuilder(new Hello("hello " + System.currentTimeMillis())).build();
}
@RequestMapping("/helloj3")
public JSendResponse<List<String>> helloJSend3() {
return JSendResponseBuilder.jSendResponseBuilder(Lists.list("hello " + System.currentTimeMillis())).build();
}
@RequestMapping("/helloj4")
public JSendResponse<List<Hello>> helloJSend4() {
return JSendResponseBuilder.jSendResponseBuilder(Lists.list(new Hello("hello " + System.currentTimeMillis()))).build();
}
@RequestMapping("/helloj5")
public void helloJSend5(Callback<JSendResponse<List<Hello>>> callback) {
callback.returnThis(JSendResponseBuilder.jSendResponseBuilder(Lists.list(new Hello("hello " + System.currentTimeMillis()))).build());
}
@RequestMapping("/helloj6")
public void helloJSend6(Callback<JSendResponse<List<String>>> callback) {
callback.returnThis(JSendResponseBuilder.jSendResponseBuilder(Lists.list(
"hello " + System.currentTimeMillis())).build());
}
@RequestMapping(value = "/helloj7", code = 221)
public void helloJSend7(Callback<JSendResponse<List<String>>> callback) {
callback.returnThis(JSendResponseBuilder.jSendResponseBuilder(Lists.list(
"hello " + System.currentTimeMillis())).build());
}
Hitting the above
# String respnose
curl http://localhost:8080/hw/hello | jq .
"hello 1446088919561"
# JSend wrapping a a string
$ curl http://localhost:8080/hw/helloj | jq .
{
"data": "hello 1446088988074",
"status": "success"
}
#JSend wrapping a domain Object Hello
$ curl http://localhost:8080/hw/helloj2 | jq .
{
"data": {
"hello": "hello 1446089041902"
},
"status": "success"
}
#JSend wrapping a list of domain objects
$ curl http://localhost:8080/hw/helloj5 | jq .
{
"data": [
{
"hello": "hello 1446089152089"
}
],
"status": "success"
}
Use jq to get pretty print JSON from QBit.
In this example we setup the admin interface as well so we can query swagger gen.
Starting up admin
public static void main(final String... args) {
final ManagedServiceBuilder managedServiceBuilder =
ManagedServiceBuilder.managedServiceBuilder().setRootURI("/");
/* Start the service. */
managedServiceBuilder.addEndpointService(new HelloWorldJSend())
.getEndpointServerBuilder()
.build().startServer();
/* Start the admin builder which exposes health end-points and meta data. */
managedServiceBuilder.getAdminBuilder().build().startServer();
System.out.println("Servers started");
...
QBit 0.9.0 RELEASE
- Admin: Added support for suggest GC.
- Queue: Added warning messages if queue has not been started and you are sending items to a stopped queue
- Health: Added a info message if you start more than one health system, and debug support.
- Spring: Fixed bug with not starting health service
- REST: Added @HideMethod annotation. Any method annotated with @HideMethod will not show up as REST end point, and will not be processes by Swagger.
- Added chained predicates support for HttpServer
- Admin: Fixed issue with stats for Heroku
- Added better URI param handling (issue fixed resource handling with URI params)
- Issue fixed with callback from REST (not getting sent to client). BoonServiceMethodCallHandler was missing onTimeout and onError. (Bug fix)
- Admin GC stats collection and GC stat count fixed
- (EndpointServer, REST support, HttpServer) Finished with response decorator and handling response in a callback.
- Added spring support for discovery and construction os QBit Services
- Added javax.inject support
- Added response decorator capability (HttpServer to support CORS)
- Added the ability for REST methods to return a HttpResponse object via callback
- Changed to using longs for stats service (StatService)
- Admin: Changed stats gathering for jvm. (no more .mb)
- Admin: Added Buffered StatsCollector for performance of stats collection
- Admin: Wrapped construction of stats collector with statscollectorbuffer
- Added better error handling: QBit does not support method overloading and should give a warning instead of failing silently
- Admin: Added support for more endpoints about the OS and VM for debugging.
- Admin: Added password screen from property map.
- Admin: Added black list for env variables and system properties
- Swagger: Clean up error handling for admin and meta-data reader
- HttpServer / EndpointServer: Improve info message so it does not say null for host
- Admin: Added admin port env var
- REST support now works with Map<String, Object>, and can converts all Value types to non-value types and sub-maps (Map<String, Object>)
QBit 0.9.0 Milestone 4
0.9.0.M4 m4 release
QBit 0.8.18 RELEASE
- Improved swagger
- Added JVM stats collection
- Created auto service discovery / consul checkin for endpoint servers and http servers
QBit 0.8.16 RELEASE
• Exposed swagger through admin
• Added admin endpoint to ManagedServiceBuilder
• Exposed admin endpoint as __admin to make it consistent with local stats collections and health
• Added support for Map<String, String> to swagger support
• Added ssl support to http server and client
• Fixed bug in BasicQueue when dealing with ArrayBlockingQueue
• Fixed ServiceBuilder so you can pass beforeMethodCall or beforeMethodCallAfterTransform
• Fixed health check NPE which was happening every hour or so
• Auto registry with endpoint builder to service discovery and health implemented
• EventBusCluster now uses Service Discovery instead of using Consul direct
QBit 0.8.15 RELEASE
- Added support for annotations by default like @JsonIgnore, @SerializedName, etc.
- Health Service was sending too many pings. The timer was not reset after send.
- Added local stats collection to store stats were they can be retrieved by 3rd party and stored.
- Added reading default web port from environment variable which is compatible with Mesos, Heroku, and Docker
- Documented and tested removing /serivces to / or /whatever
- Switched Consul client to use HTTP and not to use connection pools
- got rid of extra call to flush which was failing for proxies
from stats service. This was filling up logging for non-remote stats. - Added utility class to implement /__health and /__stats/instance endpoints
- Improved statsd replicator. making it less chatty. fixed timing.
- Improved ServiceContext support and added ability to mark a service as down for health system auto-checkins.