-
Notifications
You must be signed in to change notification settings - Fork 140
Release Notes Draft
QBit now support specifying the contentType. The default contentType is "application/json".
@RequestMapping(value = "/hello8", contentType = "application/xml", code = HttpStatus.CREATED)
public void hello8(final Callback<HttpTextResponse> callback) {
final HttpTextResponse response = HttpResponseBuilder
.httpResponseBuilder()
.setBody("<xml><hi>hello world</hi></xml>")
.setCode(201).buildTextResponse();
callback.returnThis(response);
}
Swagger meta data generation now works with HttpTextResponse
and HttpBinaryResponse
.
However if you use HttpTextResponse
or HttpBinaryResponse
there is no way to
specify a response schema so generating clients might be suspect.
Related issues:
- https://github.com/advantageous/qbit/issues/517
- https://github.com/advantageous/qbit/issues/518
- https://github.com/advantageous/qbit/issues/474
QBit now ignores Scala generated methods. Issue
Support @GET
, @DELETE
, @HEAD
, @POST
, @PUT
annotation in addition to @RequestMapping
.
The new annotations works like @RequestMapping
except they default to the corresponding HTTP methods by default.
We created a new queue sender that does not do micro-batching.
This way if batching is set to 1 on the QueueBuilder
, QBit creates a no batch queue so that we are not creating arrays and keeping the GC busy for apps that don't need micro-batching.
4) Add support to make a blocking call to a non-blocking interface via a blocking get/Future operation
Let's say you have an service as follows:
interface Foo {
void getValue(Callback<Boolean> callback);
}
static class FooService implements Foo {
@Override
public void getValue(Callback<Boolean> callback) {
callback.accept(true);
}
}
serviceQueue = ServiceBuilder.serviceBuilder().setServiceObject(new FooService()).buildAndStartAll();
foo = serviceQueue.createProxy(Foo.class);
The call is async but for a test or some other reason, you want to call it and get an immediate result (QBit goes out of its way to make everything async, but sometimes especially for testing, you want to make a synchronous call).
Now you can!
final AsyncFutureCallback<Boolean> callback = AsyncFutureBuilder
.asyncFutureBuilder().setSupportLatch(true).build(Boolean.class);
foo.getValue(callback);
ServiceProxyUtils.flushServiceProxy(foo);
final Boolean result = callback.get();
assertTrue(result);
If you set these env variable or system properties,
private final boolean checkStart = Sys.sysProp("QBIT_CHECK_START", false);
private final int checkStartWarnEvery = Sys.sysProp("QBIT_CHECK_START_WARN_EVERY", 100);
private final boolean checkQueueSize = Sys.sysProp("QBIT_CHECK_QUEUE_SIZE", false);
private final int checkQueueSizeWarnIfOver = Sys.sysProp("QBIT_CHECK_QUEUE_SIZE_WARN_IF_OVER", 10);
export QBIT_CHECK_START=true
export QBIT_CHECK_START_WARN_EVERY=5
export QBIT_CHECK_QUEUE_SIZE=true
export QBIT_CHECK_QUEUE_SIZE_WARN_IF_OVER=2
Then QBit will check to see if a queue was started and issues warning if it was not started. You can leave this on and check every 100 times or you can check every time for debugging.
You can also instruct QBit to check for queues whose size are over a certain limit.
These setting are off by default and are mainly used during development to make sure you have setup QBit correctly.
You should not really use these outside of development as there is a performance cost to the checks.
Suggested production or perf tuning setup:
export QBIT_CHECK_START=false
export QBIT_CHECK_QUEUE_SIZE=false
Suggested dev environment or dev box
export QBIT_CHECK_START=true
export QBIT_CHECK_START_WARN_EVERY=5
export QBIT_CHECK_QUEUE_SIZE=true
export QBIT_CHECK_QUEUE_SIZE_WARN_IF_OVER=2
Suggested integration server or server that does not get tons of traffic or load.
Suggested dev environment or dev box
export QBIT_CHECK_START=true
export QBIT_CHECK_QUEUE_SIZE=true
export QBIT_CHECK_START_WARN_EVERY=100
export QBIT_CHECK_QUEUE_SIZE_WARN_IF_OVER=50
Added support to detect when the connection is closed.
Issue 526. Docs added to Health System Documents
@RequestMapping(value = "/todo")
@Api(value = "/todo", consumes = "", description = "Todod")
public class TodoService {
...
/**
* Used to call the queue. This gets called when our service queue is empty or has reached its limit.
*/
@QueueCallback({QueueCallbackType.LIMIT, QueueCallbackType.EMPTY, QueueCallbackType.IDLE})
public void process() {
reactor.process();
this.jmsConnected = jmsConnectedRef.get();
final ServiceQueue serviceQueue = ServiceContext.serviceContext().currentService();
if (!jmsConnected) {
serviceQueue.setFailing();
} else {
serviceQueue.recover();
}
}
The above checks to see if JMS is up. If it is not up, then this service fails. If JMS is up, then the service is marked as recovered. The two ways a service can fail is if it never checks in, or if it marks itself as failed.
Once a service is marked unhealthy. The health end points will report this status.
If you have local health end point check installed then this will show up as failed.
$ curl http://localhost:8090/__health -v
* Trying ::1...
* Connected to localhost (::1) port 8090 (#0)
> GET /__health HTTP/1.1
> Host: localhost:8090
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 500 SERVER ERROR
< Content-Type: application/json
< Content-Length: 6
<
* Connection #0 to host localhost left intact
"fail"
The admin end point returns true 200 if ok and false 200 if not ok.
$ curl http://localhost:7779/__admin/ok -v
* Trying ::1...
* Connected to localhost (::1) port 7779 (#0)
> GET /__admin/ok HTTP/1.1
> Host: localhost:7779
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 5
<
* Connection #0 to host localhost left intact
false
Once the service recovers, in this case, it is able to connect to JMS again.
$ curl http://localhost:7779/__admin/ok -v
* Trying ::1...
* Connected to localhost (::1) port 7779 (#0)
> GET /__admin/ok HTTP/1.1
> Host: localhost:7779
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 4
<
* Connection #0 to host localhost left intact
true
$ curl http://localhost:8090/__health -v
* Trying ::1...
* Connected to localhost (::1) port 8090 (#0)
> GET /__health HTTP/1.1
> Host: localhost:8090
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 4
<
* Connection #0 to host localhost left intact
"ok"
Then things go back to normal.
We added some new annotations that work like @RequestMapping but lead to more terse annotation usage.
The @POST
annotation changes the status code to HttpStatus.CREATED
as an HTTP POST
is
a create or add operation while a PUT
is a modify, edit, update operation.
@PUT, @POST, @GET, @HEAD,
and @DELETE
are used to annotated methods and work very much
like @RequestMapping except the method is already set and in the case of @POST
the HTTP Status
code is changed to CREATED.
This was added to make the annotation more terse and it also is a bit more familiar to someone who is used to JAX-RS.
This allows you to specify a REST body of Map<String, Object> and then boon will do the right thing and keep parsing Maps and Lists no matter how deeply nested they are.
package io.advantageous.qbit.example.rawmap;
import io.advantageous.qbit.QBit;
import io.advantageous.qbit.admin.ManagedServiceBuilder;
import io.advantageous.qbit.annotation.RequestMapping;
import io.advantageous.qbit.annotation.http.PUT;
import io.advantageous.qbit.json.JsonMapper;
import io.advantageous.qbit.reactive.Callback;
import java.util.Map;
@RequestMapping("/map")
public class HandleMap {
private final JsonMapper jsonMapper = QBit.factory().createJsonMapper();
@PUT("/put")
public void putMap(final Callback<Map<String,Object>> httpCallback,
final Map<String, Object> map) {
httpCallback.returnThis(map);
}
public static void main(final String... args) {
final ManagedServiceBuilder managedServiceBuilder = ManagedServiceBuilder.managedServiceBuilder().setRootURI("/");
managedServiceBuilder.addEndpointService(new HandleMap());
managedServiceBuilder.getEndpointServerBuilder().build().startServer();
}
}
Then you can send complex maps to this end point and see them returned correctly.
$ curl -X PUT -H "Content-Type: application/json" -d '{"foo":{"ok":"Rick is ok","root":{"fooQuery":{"interDimensionsFilter":[{"dimension":""}],"temporalDimension":{"field":"started_at"},"staggregations":[{"metricName":"n_fail","function":"average"}],"aggregateBy":["your_mom"]},"xAxisTitle":"","title":"panel test","type":"bar","tool":12,"disorder":"0","seriesType":"time","yAxisTitle":""}}}' http://localhost:8080/map/put | jq .
{
"foo": {
"ok": "Rick is ok",
"root": {
"fooQuery": {
"interDimensionsFilter": [
{
"dimension": ""
}
],
"temporalDimension": {
"field": "started_at"
},
"staggregations": [
{
"metricName": "n_fail",
"function": "average"
}
],
"aggregateBy": [
"your_mom"
]
},
"xAxisTitle": "",
"title": "panel test",
"type": "bar",
"tool": 12,
"disorder": "0",
"seriesType": "time",
"yAxisTitle": ""
}
}
}
QBit Website What is Microservices Architecture?
QBit Java Micorservices lib tutorials
The Java microservice lib. QBit is a reactive programming lib for building microservices - JSON, HTTP, WebSocket, and REST. QBit uses reactive programming to build elastic REST, and WebSockets based cloud friendly, web services. SOA evolved for mobile and cloud. ServiceDiscovery, Health, reactive StatService, events, Java idiomatic reactive programming for Microservices.
Reactive Programming, Java Microservices, Rick Hightower
Java Microservices Architecture
[Microservice Service Discovery with Consul] (http://www.mammatustech.com/Microservice-Service-Discovery-with-Consul)
Microservices Service Discovery Tutorial with Consul
[Reactive Microservices] (http://www.mammatustech.com/reactive-microservices)
[High Speed Microservices] (http://www.mammatustech.com/high-speed-microservices)
Reactive Microservices Tutorial, using the Reactor
QBit is mentioned in the Restlet blog
All code is written using JetBrains Idea - the best IDE ever!
Kafka training, Kafka consulting, Cassandra training, Cassandra consulting, Spark training, Spark consulting
Tutorials
- QBit tutorials
- Microservices Intro
- Microservice KPI Monitoring
- Microservice Batteries Included
- RESTful APIs
- QBit and Reakt Promises
- Resourceful REST
- Microservices Reactor
- Working with JSON maps and lists
__
Docs
Getting Started
- First REST Microservice
- REST Microservice Part 2
- ServiceQueue
- ServiceBundle
- ServiceEndpointServer
- REST with URI Params
- Simple Single Page App
Basics
- What is QBit?
- Detailed Overview of QBit
- High level overview
- Low-level HTTP and WebSocket
- Low level WebSocket
- HttpClient
- HTTP Request filter
- HTTP Proxy
- Queues and flushing
- Local Proxies
- ServiceQueue remote and local
- ManagedServiceBuilder, consul, StatsD, Swagger support
- Working with Service Pools
- Callback Builders
- Error Handling
- Health System
- Stats System
- Reactor callback coordination
- Early Service Examples
Concepts
REST
Callbacks and Reactor
Event Bus
Advanced
Integration
- Using QBit in Vert.x
- Reactor-Integrating with Cassandra
- Using QBit with Spring Boot
- SolrJ and service pools
- Swagger support
- MDC Support
- Reactive Streams
- Mesos, Docker, Heroku
- DNS SRV
QBit case studies
QBit 2 Roadmap
-- Related Projects
- QBit Reactive Microservices
- Reakt Reactive Java
- Reakt Guava Bridge
- QBit Extensions
- Reactive Microservices
Kafka training, Kafka consulting, Cassandra training, Cassandra consulting, Spark training, Spark consulting