Closed wso-ot closed 6 years ago
Try returning a CompleteableFuture return mono.toFuture ?
If that works, a Provider could be created to adapt this.
Doesn't work... Here's what I have at the resource:
@Component
@Slf4j
//@RequestMapping("/v9/restaurants")
@Path("/v9/restaurants")
public class RestaurantsResource {
@Autowired private RestaurantService restaurantService;
@GET
@Path("/{rid}")
@Produces(MediaType.APPLICATION_JSON_UTF8_VALUE)
public CompletableFuture<Restaurant> getRestaurtant(@PathParam("rid") int rid){
return restaurantService.getRestaurantMono(rid).toFuture();
}
// @RequestMapping(value = "/{rid}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
// @GET
// public Mono<Restaurant> getRestaurtant(@PathVariable("rid") int rid){
//
// return restaurantService.getRestaurantMono(rid);
//
// }
}
Any more info than "doesn't work"?
The request is sent with this:
curl -X GET \ http://localhost:8900/v9/restaurants/1811 \ -H 'cache-control: no-cache' \ -H 'content-type: application/json' \ -H 'postman-token: a3e8e1f7-ea89-f59a-36dd-17e8a0fae685'
And the result:
{
"timestamp": 1526413378294,
"path": "/v9/restaurants/1811",
"status": 404,
"error": "Not Found",
"message": "No matching handler"
}
The restaurantService forwards the request to a ReactiveCrudRepository. The method returns a Mono. It remains a Mono until the code above
The application configuration class:
@ComponentScan
@EnableDiscoveryClient
@EnableAsync
@EnableScheduling
@EnableWebFlux
@RestReactiveHttpServer
@EnableReactiveMongoRepositories
@EnableAutoConfiguration
public class ServiceConfiguration {
}
The main application class:
/**
* The main application class
*/
@Configuration
@Import(value = {
MongoConfiguration.class,
ServiceConfiguration.class
})
public class RestaurantServiceApplication {
public static void main(final String[] args) {
OTApplication.run(RestaurantServiceApplication.class, args);
}
@Bean
public ServiceInfo serviceInfo() {
return () -> "restaurant-service";
}
}
I'm running this in my IDE, running just the main class. With no argument.
And the bootstrap.yml
spring:
cloud:
config:
enabled: false
failFast: false
uri: https://opentable:***@config-ci-uswest2.otenv.com/
application:
name: coresvc-restaurant-service
---
application.yml
ot:
announce:
enabled: false
service-type: restauarnt-service
discovery:
mode: OT
servers: proxy://discovery-ci-sf.otenv.com/
graphite:
graphite-host: carbon-qa-sf.otenv.com
restaurant-service:
mongo-connect-timeout: 500
mongo-server-selection-timeout: 500
spring:
data:
mongodb:
uri: mongodb://beaversUser:***@beavers-01-pp-sf.otenv.com:27017,beavers-02-pp-sf.otenv.com:27017,beavers-03-pp-sf.otenv.com:27017/Restaurants-v3?replicaSet=beavers;authSource=admin;safe=true;readPreference=primary;wtimeoutMS=180000
logging:
level:
org.springframework.jdbc.core.JdbcTemplate: WARN
org.springframework.data.mongodb.core.MongoTemplate: WARN
#root: TRACE
server:
port: ${PORT0:8900}
{ "timestamp": 1526413378294, "path": "/v9/restaurants/1811", "status": 404, "error": "Not Found", "message": "No matching handler" }
We don't generate this. Further, please run it locally and prove it actually responds on that endpoint when you manually hit it - Change it for example to return a string.
Furthermore, not that there aren't valid reasons for reactive/async responses, but do you actually have metrics/evidence that you actually do need it?
On the 404 response:
The problem is, we can't get it to response with anything if we use @Path and @Get annotations, i.e. JAX-RS style annotations. So Jersey or Resteasy is not picking the resource up. Here's a simpler thing that I've tried:
package com.opentable.coresvc.restaurantservice.resource;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.concurrent.CompletableFuture;
@Component
//@RestController
@Slf4j
//@RequestMapping("/v9/restaurants")
@Api("Simple Test")
@Path("/simple")
public class SimpleResource {
@GET
@Path("/hello")
@Produces(MediaType.APPLICATION_JSON_UTF8_VALUE)
public CompletableFuture<String> getHello(){
return Mono.just("Hello World").toFuture();
}
}
This is the version that will work:
package com.opentable.coresvc.restaurantservice.resource;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.concurrent.CompletableFuture;
//@Component
@RestController
@Slf4j
@RequestMapping("/simple")
@Api("Simple Test")
//@Path("/simple")
public class SimpleResource {
@RequestMapping(value = "/hello", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Mono<String> getHello(){
return Mono.just("Hello World");
}
}
On why using Reactive: The API you are seeing is the simple case. We have an endpoint that will return all Restaurants from the MongoDB. That's 1/2 million restaurants. The main user is the restaurant search indexer. So we will be experimenting with this to see if performance improves. The existing Restaurant API is written in Node JS and is constantly leaking memory.
Is there an issue with using the spring annotations? also if you're going to use Spring WebFlux (reactive spring) You want to return Mono
I'm gonna close this, because the reason on why things doesn't work is explained here. Let's move the conversation to there instead.
We are working on this: https://github.com/opentable/restaurant-service
We tried to use the JAX-RS style annotations (@Path, @Get, etc) in the RestaurantResource but it's not loading the controller. It works when we switch to the Spring REST style annotations with "@RestController" and "@RequestMapping".
Maybe something about the Resteasy context not being loaded in the Reactive init path?