-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BatchHystrixCommand has no sence and doesn't collapse requests #689
Comments
There should be a convenient way to override reduce logic assume should be a new annotation to mark |
This looks like something in the hystrix-javanica module. /cc @dmgcodevil @sawano |
Hi @anton-antonov, probably I didn't get it completely when was implementing collapser feature, therefore lets refresh it and figure out a gaps in my understanding in order to fix it. A method annotated with HystrixCollapser is invoked within CommandCollapser. CommandCollapser uses a method arguments (it's an array) to create collapsed requests and afterwards creates BatchHystrixCommand to make underlying calls. BatchHystrixCommand is invoked once for collapsed requests that prepared by CommandCollapser. Action is invoked as many times as much elements in Collection<HystrixCollapser.CollapsedRequest<Object, Object>> and it's used to invoke a method but BatchHystrixCommand is invoked once per collection of CollapsedRequest objects. In my opinion there is no incorrect behavior, isn't ? final Object[] args = (Object[]) request.getArgument(); here args is args of an annotated method. @HystrixCommand
@HystrixCollapser(reducer="getUserReducer")
public User getUser(String id, String name) {
return new User(id, name + id);
}
private void getUserReducer(List<Optional<Object>> batchResponse,
Collection<CollapsedRequest<Object, Object>> collapsedRequests); Or we can add interface Reducer with single method and specify the type of certain implementation in @HystrixCollapser. WDYT ? |
Hi @dmgcodevil, thanks for your response. Yes, Let's say I have a command like this @HystrixCommand()
@HystrixCollapser()
public String getValue(Long id) {
//here I made a heavy backend call to remote service
return this.client.getValue(id);
} then I perform the following call with thousands of threads (1000 requests/sec) myCommand.getValue(10L); Notice that all 1000 requests are calling the same ID parameter and I expect that backend service will be called only once or at least the less number of times then client does. More over current implementation reduces all benefits at all, look: With custom reducing logic it should be possible to utilise backend service batching facilities if backend service has something like this: public Map<Long, String> getValues(List<Long> ids); |
Hi @anton-antonov, thanks for the response @CacheResult
@HystrixCommand
public String getValue(@CacheKey Long id) {
return this.client.getValue(id);
} I got your point about collapser, but I don't have any ideas how to implement it using annotations. |
Thanks, @dmgcodevil. Point here is just about collapsing exact identical backend calls and it is possible even with annotations.
As a conclusion: |
Thus the collapser will play same role as Hystrix cache, it just will deduplicate same parameters and that's all, right ? @mattrjacobs what do you think about it ? |
Stepping back, the reason that collapsers exist is to enable batching that is performed on behalf of the caller without the caller being forced to do any batching-specific logic. This is different from Hystrix request caching.
So the 2 major pieces of machinery needed for a collapser implementation are:
If you are able to represent those as annotations, then you should be able to achieve your goal. I'm not familiar enough with the |
Thanks @mattrjacobs. Actually it seems like I got it almost correctly originally but implemented it a bit incorrectly. Now I see how it can be implemented: @HystrixCollapser(command="getByValues")
String getByValue(Integer val){
return null; // this is stab, this line shouldn't invoked, instead of it the batch command will be executed
}
@HystrixCommand(reducer= CustomReducer.class) // reducer is optional field because it must provide default implementation
List<String> getByValues(List<Integer> values){
// network call
}
interface Reducer<ResponseType, RequestArgumentType> {
ResponseType reduce(RequestArgumentType requestArg);
}
class CustomReducer implements Reducer<String, Integer> {
String reduce(Integer requestArg) {
return "ValueForKey: " + requestArg;
}
} What do you think? (@anton-antonov, @mattrjacobs) |
This looks generally on the right path. In |
Thanks @mattrjacobs. In my opinion it's not reducer it's more like mapper. Reducing logic wouldn't be changed, it will be implemented as in core: @Override
protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) {
int count = 0;
for (CollapsedRequest<String, Integer> request : requests) {
request.setResponse(batchResponse.get(count++));
}
} Mapper gives the ability to manage mapping logic at reducing step and it's just additional feature, but I'm not sure that it gives significant advantages, but probably will be useful in some cases. Ok, so lets summarize it: @HystrixCollapser(command="getByValues", mapper= CustomMapper.class) // mapper is optional
String getByValue(Integer val){
return null; // this is stab, this line shouldn't invoked, instead of it the batch command will be executed
} Command: @HystrixCommand
List<String> getByValues(List<Integer> values){
// network call
} interface Mapper<ResponseType, RequestArgumentType> {
ResponseType map(RequestArgumentType requestArg);
} If it's ok then I will start implementation. Also please assign this issue to me. Thanks. |
As far as I can tell, that looks right to me. |
Tried to assign to you, but that only seems to work for people in the Netflix Github team. I'll try to get that working |
Netflix#689: updated wiki: collapser section
Please see PL |
Netflix#689: fix wiki format
@mattrjacobs did you change code of projects to use jdk 6 ? |
Yes, JDK6 now, as of Hystrix 1.4.3. See #731 |
@dmgcodevil I compiled and tested yours fork. Everything seems to work just fine. Is there any chance to include support for void methods? For example something like that: @HystrixCollapser(commandKey = "storeUsers")
public void storeUser(String id) {
}
@HystrixCommand
public void storeUsers(List<String> ids) {
} |
Hi @MariuszNET, this changes were merged to upstream one week ago and I guess it's available in hystrix 4.x.x @HystrixCollapser(commandKey = "storeUsers")
public Future<String> storeUser(String id) {
return null;
}
@HystrixCommand
public List<String> storeUsers(List<String> ids) {
// put your logic here
return ids;
} Or create a wrapper for your code if you cant change API. |
@dmgcodevil Thanks for info about merge - I missed this. Version 1.4.4 contains changes and works well. Thanks, |
BatchHystrixCommand
calls underlying action as many times as it's requested and thus there is no benefit of collapse requests feature at all.Actual processing
Optional.of(fallbackEnabled ? processWithFallback(args) : process(args))
should be done only once for same set of request args.The text was updated successfully, but these errors were encountered: